上篇完成了商品从详情页添加到购物车界面的逻辑,现在在购物车界面已经可以拿到购物车里的商品列表,现在要处理在购物车界面的一些逻辑。
功能拆分
购物车界面还是有些东西的,涉及到多处数据的同步更改,下面对功能进行拆分:
- 商品选择和取消选择
- 总金额计算
- 全选
经过上篇操作现在在购物车界面已经可以拿到要添加到购物车页面的商品列表。单个商品的数据结构如下:
{
image: "https://i.loli.net/2020/04/19/m1v4HcARnMsadUq.jpg",
title: "2060款手机傻妞为你服务",
desc: "十年老店",
price: "29.98",
iid: "cemcoe",
count: 4
}
有了这些数据就可以进行渲染展示了。上篇已进行编码,这里不再重复。
商品是否选中
第一个功能点是商品的选中和不选中。
先是视觉上的选中和取消选中。
明显是切换,这样的场景在 Vue 组件 | 如何从零封装一个tabbar组件 时有遇到,选中时红色图标,没选中时灰色图标。当时是准备了两组图片,当用户点击时切换图片资源。这里也可以使用上述方案。
但有没有更好的方式?
这里的选择按钮并不复杂,其实改变个背景色就好了。
这里用到动态绑定 class 的方案,当选中时给个红色的背景,没选中时给个灰色背景。重点是定义一个变量决定是否给元素添加对应的类名。
上面就是视觉上的逻辑实现。
下面是功能上的,首先要知道商品当前的状态,即是否被选中?当商品对应的按钮被选中时,要放到商品结算列表,用于最后总金额的计算。
上面的商品对象并没有我们需要的变量,不妨暂定 checked 并到 Vuex 中定义。
// mutations.js
export default {
// mutations 唯一目的是修改state中状态
// mutations 每个方法尽可能完成单一事件
[ADD_COUNTER](state, payload) {
payload.count++
},
[ADD_TO_CART](state, payload) {
payload.checked = true
state.cartList.push(payload)
}
}
这个 checked 默认是 true,即用户在详情页将商品添加到购物车时商品默认是选中的状态。
有了 checked 这个值我们就可以来判断商品按钮的状态了。对按钮进行事件监听,并在用户点击时更改按钮的状态。
methods: {
checkClick() {
this.itemInfo.checked = !this.itemInfo.checked
console.log("改变商品选择状态成功")
}
}
在 Vuex 中定义了 checked 属性后,此时一个商品对象的数据类型变成了这样:
{
image: "https://i.loli.net/2020/04/19/m1v4HcARnMsadUq.jpg",
title: "2060款手机傻妞为你服务",
desc: "十年老店",
price: "29.98",
iid: "cemcoe",
count: 4,
checked: true
}
总金额的计算
底部的功能栏是三栏布局,布局样式这里就不写了,flex 一把梭。
那么此时的问题就变成了一道数学题。
如何计算总金额?
总金额 = 选中的商品 * 数量 * 单价
现在的问题是找到这些变量,看一下商品对象的数据类型不难找到。
checked: 是否选中
count: 数量
price: 单价
问题转变成了对象数组的求和问题,先找到 cartList 中 checked 值为 true 的商品对象,然后找到这些对象的 count 和 price,将这些变量套到公式里。
totalPrice() {
return (
"¥" +
this.$store.state.cartList
.filter(item => {
return item.checked
})
.reduce((preValue, item) => {
return preValue + item.price * item.count
}, 0)
)
}
上面用到了数组的两个高阶函数,filter 用于过滤数组中符合条件的元素,reduce 用于将数组中的元素进行汇总成一个值。
全选
在该页面有两种对号,一种是商品前面,一种就是底部的全选。
全选的逻辑是当商品全部被选中时,全选是红色,否则是灰色。
点击全选,商品要么全变红,要么全变灰色。
computed:{
checkLength() {
return this.$store.state.cartList.filter(item => {
return item.checked
}).length
},
isSelectAll() {
// 全选状态
if (this.$store.state.cartList.length === 0) return false
return !this.$store.state.cartList.find(item => !item.checked)
}
}
methods: {
checkClick() {
if (this.isSelectAll) {
// 全部选中
console.log("已全选")
this.$store.state.cartList.forEach(item => (item.checked = false))
} else {
// 有部分未选择
console.log("有部分未选中")
this.$store.state.cartList.forEach(item => (item.checked = true))
}
}
}
先来两个计算属性,checkLength 被选中商品的数量,isSelectAll 是否处于全选的状态。计算属性用来控制全选按钮的状态。
而后是功能代码 checkClick,用来响应用户的点击,当处于全选状态点击时,要将每个商品对象的 checked 属性改成 false。如果有部分未选中点击时,将全部的商品对象的checked 属性改成 true。
checkClick 通过改变商品的 checked 属性影响 checkLength,进而影响 isSelectAll,最总影响按钮的展示。
购物车完。