// 有效商品列表
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>¥{{ goods.nowPrice }}</p><p>比加入时降价<span class="red">¥{{ 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">¥{{ 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">¥{{ cartStore.selectedAmount }}</span></span><a @click="checkout" href="javascript:;" class="btn">下单结算</a></div></div>
2. 购物车页面-单选操作-本地
// 更新购物车中的商品信息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 和 countreturn new Promise((resolve, reject) => {const userStore = useUserStore()if (userStore.profile.token) {// 已登录} else {// 未登录this.updateGoods(newGoods)resolve()}})},
<!-- 通过$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. 购物车页面-删除操作-本地
// 删除购物车中的商品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.jsimport { 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. 购物车页面-批量删除-本地
// 批量删除购物车商品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: '成功删除所选商品' })})})
}