vue3项目-小兔鲜儿笔记-购物车02

1.购物车页面-列表展示-本地

  • 准备已选择的商品列表数据,已选择的商品件数以及需要支付的金额

  • 渲染模板

// 有效商品列表
validList(state) {
  return state.list.filter((goods) => goods.isEffective && goods.stock > 0)
},
// 有效商品件数
validTotal() {
  return this.validList.reduce((p, c) => {
    return p + c.count
  }, 0)
},
// 有效商品总金额
validAmount() {
  return this.validList.reduce((p, c) => {
    return p + Number((c.nowPrice * c.count).toFixed(2))
  }, 0)
},
// 选中商品列表
selectedList() {
  return this.validList.filter((goods) => goods.selected)
},
// 选中商品件数
selectedTotal() {
  return this.selectedList.reduce((p, c) => {
    return p + c.count
  }, 0)
},
// 选中商品总金额
selectedAmount() {
  return this.selectedList.reduce((p, c) => {
    return p + Number((c.nowPrice * c.count).toFixed(2))
  }, 0)
},
// 是否全选
isCheckAll() {
  return (
    this.validList.length === this.selectedList.length &&
    this.selectedList.length !== 0
  )
}
          <!--     有效商品     -->
          <tbody>
            <tr v-if="cartStore.validList.length === 0">
              <!-- 合并6列的宽度 -->
              <td colspan="6">
                <cart-none />
              </td>
            </tr>
            <tr v-for="goods in cartStore.validList" :key="goods.skuId">
              <td>
                <!--      通过$event拿到change事件返回的默认参数       -->
                <xtx-checkbox
                  @change="checkOne(goods.skuId, $event)"
                  :modelValue="goods.selected"
                />
              </td>
              <td>
                <div class="goods">
                  <router-link to="/">
                    <img v-lazy="goods.picture" alt="" />
                  </router-link>
                  <div>
                    <p class="name ellipsis">{{ goods.name }}</p>
                    <!-- 选择规格组件 -->
                    <CartSku
                      :attrsText="goods.attrsText"
                      :skuId="goods.skuId"
                      @change="($event) => updateCartSku(goods.skuId, $event)"
                    />
                  </div>
                </div>
              </td>
              <td class="tc">
                <p>&yen;{{ goods.nowPrice }}</p>
                <p>
                  比加入时降价
                  <span class="red">
                    &yen;{{ goods.nowPrice - goods.price }}
                  </span>
                </p>
              </td>
              <td class="tc">
                <xtx-numberbox
                  :max="goods.stock"
                  @change="($event) => changeCount(goods.skuId, $event)"
                  :modelValue="goods.count"
                />
              </td>
              <td class="tc">
                <p class="f16 red">
                  &yen;{{ Number((goods.nowPrice * goods.count).toFixed(2)) }}
                </p>
              </td>
              <td class="tc">
                <p><a href="javascript:;">移入收藏夹</a></p>
                <p>
                  <a
                    @click="deleteCart(goods.skuId)"
                    href="javascript:;"
                    class="green"
                  >
                    删除
                  </a>
                </p>
                <p><a href="javascript:;">找相似</a></p>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
      <!--   操作栏   -->
      <div class="action">
        <div class="batch">
          <xtx-checkbox @change="checkAll" :modelValue="cartStore.isCheckAll">
            全选
          </xtx-checkbox>
          <ul>
            <li>
              <a @click="batchDeleteCart" href="javascript:;">删除所选商品</a>
            </li>
            <li><a href="javascript:;">移入收藏夹</a></li>
          </ul>
        </div>
        <div class="wrapped">
          <span class="totalCount">共 {{ cartStore.validTotal }} 件商品,</span>
          <span class="validCount">
            已选择 {{ cartStore.selectedTotal }} 件,
          </span>
          <span class="validAmount">
            商品合计:
            <span class="red">&yen;{{ cartStore.selectedAmount }}</span>
          </span>
          <a @click="checkout" href="javascript:;" class="btn">下单结算</a>
        </div>
      </div>

 

2. 购物车页面-单选操作-本地

  • 定义修改购物车商品选中状态的actions

// 更新购物车中的商品信息
    updateGoods(newGoods) {
      // newGoods中有些字段可能不完整,要先判断
      // newGoods中必须要有skuId,这样才能找到对应商品
      const oldGoods = this.list.find((goods) => goods.skuId === newGoods.skuId)
      for (const key in newGoods) {
        if (
          newGoods[key] !== null &&
          newGoods[key] !== '' &&
          newGoods[key] !== undefined
        ) {
          oldGoods[key] = newGoods[key]
        }
      }
    },
        
    // 修改购物车的状态(选中,数量)
    asyncUpdateGoods(newGoods) {
      // 必须有skuId,可能有:selected 和 count
      return new Promise((resolve, reject) => {
        const userStore = useUserStore()
        if (userStore.profile.token) {
          // 已登录
        } else {
          // 未登录
          this.updateGoods(newGoods)
          resolve()
        }
      })
    },
  • 在购物车页面单选的复选框处理change事件从而处理选中状态

                <!--      通过$event拿到change事件返回的默认参数       -->
                <xtx-checkbox
                  @change="checkOne(goods.skuId, $event)"
                  :modelValue="goods.selected"
                />
// 单选商品
const checkOne = (skuId, selected) => {
  cartStore.asyncUpdateGoods({ skuId, selected })
}

 

3. 购物车页面-全选操作-本地

  • 定义actions

    // 做有效商品的全选/反选
    checkAllCart(selected) {
      return new Promise((resolve, reject) => {
        const userStore = useUserStore()
        if (userStore.profile.token) {
          // 已登录
        } else {
          // 未登录
          const validList = this.list.filter(
            (goods) => goods.isEffective && goods.stock > 0
          )
          // 根据传来的selected状态进行全选/反选
          validList.forEach((goods) => {
            this.updateGoods({ skuId: goods.skuId, selected })
          })
        }
      })
    },
  • 在购物车页面调用全选

                <xtx-checkbox
                  @change="checkAll"
                  :modelValue="cartStore.isCheckAll"
                >
// 全选与反选商品
const checkAll = (selected) => {
  cartStore.checkAllCart(selected)
}

 

4. 购物车页面-删除操作-本地

  • 定义actions

    // 删除购物车中的商品
    deleteCart(skuId) {
      const index = this.list.findIndex((goods) => goods.skuId === skuId)
      this.list.splice(index, 1)
    },
    //结合登录逻辑和未登录逻辑的删除购物车中的商品
    asyncDeleteCart(skuId) {
      return new Promise((resolve, reject) => {
        const userStore = useUserStore()
        if (userStore.profile.token) {
          // 已登录
        } else {
          // 未登录
          this.deleteCart(skuId)
          resolve()
        }
      })
    }
  • 在购物车页面调用删除

// 删除商品
const deleteCart = (skuId) => {
  Confirm({ title: '温馨提示', text: '您确认从购物车中删除该商品吗?' })
    .then(() => {
      cartStore.asyncDeleteCart(skuId).then(() => {
        Message({ type: 'success', text: '成功删除商品' })
      })
    })
    .catch((e) => {
      console.log(e)
    })
}

 

5. 封装确认框组件

  • 实现组件基础结构

<template>
  <div class="xtx-confirm" :class="{ fade: fade }">
    <div class="wrapper" :class="{ fade: fade }">
      <div class="header">
        <h3>{{ title }}</h3>
        <a
          @click="cancel"
          href="javascript:;"
          class="iconfont icon-close-new"
        ></a>
      </div>
      <div class="body">
        <i class="iconfont icon-warning"></i>
        <span>{{ text }}</span>
      </div>
      <div class="footer">
        <xtx-button @click="cancel" size="mini" type="gray">取消</xtx-button>
        <xtx-button @click="submit" size="mini" type="primary">确认</xtx-button>
      </div>
    </div>
  </div>
</template>
const props = defineProps({
  title: {
    type: String,
    default: '温馨提示'
  },
  text: {
    type: String,
    default: ''
  },
  cancelCallback: {
    type: Function
  },
  submitCallback: {
    type: Function
  }
})

逻辑分析:

Confirm.js

import { createVNode, render } from 'vue'
import XtxConfirm from './xtx-confirm.vue'
// 1.导入被创建的组件
// 2.使用createVNode创建组件的虚拟DOM
// 3.准备一个DOM容器装载组件节点
// 4.使用render函数渲染组件的虚拟节点为真实的DOM节点,并挂载到DOM容器上
const div = document.createElement('div')
div.classList.add('xtx-confirm-container')
document.body.appendChild(div)

export default function ({ title, text }) {
  // 返回一个promise对象,点取消和确认都要销毁组件
  return new Promise((resolve, reject) => {
    
    // 点击取消,触发reject并销毁组件
    const cancelCallback = () => {
      render(null, div) // 销毁组件
      reject(new Error('取消'))
    }
    // 点击确认,触发resolve并销毁组件
    const submitCallback = () => {
      render(null, div)
      resolve()
    }

    const vnode = createVNode(XtxConfirm, { title, text, cancelCallback, submitCallback })
    render(vnode, div)
  })
}

在调用删除商品时使用确认框:

// 删除商品
const deleteCart = (skuId) => {
  Confirm({ title: '温馨提示', text: '您确认从购物车中删除该商品吗?' })
    .then(() => {
      cartStore.asyncDeleteCart(skuId).then(() => {
        Message({ type: 'success', text: '成功删除商品' })
      })
    })
    .catch((e) => {
      console.log(e)
    })
}

 

6. 购物车页面-批量删除-本地

  • 定义批量删除商品的actions

// 批量删除购物车商品
    batchDeleteCart() {
      return new Promise((resolve, reject) => {
        const userStore = useUserStore()
        if (userStore.profile.token) {
          // 已登录
        } else {
          // 未登录
          // 遍历选中商品列表,一个个删除
          const selectedList = this.list.filter((goods) => goods.selected)
          selectedList.forEach((goods) => {
            this.deleteCart(goods.skuId)
          })
        }
      })
    },

 在购物车页面中点击删除所选商品时调用批量删除商品

// 批量删除商品
const batchDeleteCart = () => {
  Confirm({ text: '您确认从购物车中删除所选商品吗?' }).then(() => {
    // 点击确认按钮,触发resolve(),使用.then获得resolve的回调
    cartStore.batchDeleteCart().then(() => {
      Message({ type: 'success', text: '成功删除所选商品' })
    })
  })
}

 

posted @   jzhF1ash  阅读(64)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
点击右上角即可分享
微信分享提示