最近在练习商城项目,记录下实现购物车三级选中的过程(小白一个,水平很菜)
效果图:
实现:
1.全选时所有商品+店铺全部选中;反之全部取消选中
2.店铺选中时,当前店铺内所有商品选中;反之取消选中
3.店铺内商品全选 → 所属店铺选中;反之取消选中店铺
4.店铺+所有商品全选 → 全选按钮选中;反之取消选中
首先说明一下,我使用了vuex来管理购物车数据,所有改变按钮状态的方法都写在mutaition里
const state = {
cartList: [], // 购物车列表
totalCount: 0,
allChecked: false, // 全选
shopCheckedNum: 0, // 选中的店铺数量
/**
* cartList: [
* {
* shopName,
* shopChecked: false, // 店铺选中
* proCheckedNum: 0, // 当前店铺商品选中数量
* cartGoodsInfo: [
* {iid,styleName,proChecked...} // 里边是商品的各种信息,proChecked是商品选中状态
* {...}
* ]
* },
* {...}
* ]
*/
};
html选择按钮部分
// 这是选择按钮,我把它封装成了一个组件 chooseClass接收父组件传值改变选中时的样式
// 商品的选中按钮
<cart-choose
:chooseClass="$store.state.cartList[index].products[key].proChecked"
@click.native.stop="proCheckedClick(index, key)"
/>
// 店铺的选择按钮 (我把店铺列表和商品分成了两个组件,index是传给店铺列表内商品的)
<cart-choose
:index="index"
:chooseClass="$store.state.cartList[index].shopChecked"
@click.native="shopCheckedClick(index)"
/>
// 全选按钮
<cart-choose :chooseClass="$store.state.allChecked" />
商品,店铺,全选按钮的点击方法
// index:店铺索引值 key:当前商品在当前店铺内的索引值
proCheckedClick(index, key) {
this.$store.dispatch("ProChecked", { index, key });
},
shopCheckedClick(index) {
this.$store.dispatch("ShopChecked", index);
},
allChecked() {
this.$store.dispatch("AllChecked");
},
mutations
// 单个商品选中
proCheckedTrue(state, { index, key }) {
const cartList = state.cartList;
cartList[index].products[key].proChecked = true;
cartList[index].proCheckedNum += 1; // 商品数量+1
},
// 单个商品取消选中
proCheckedFalse(state, { index, key }) {
const cartList = state.cartList;
cartList[index].products[key].proChecked = false;
cartList[index].proCheckedNum -= 1;
},
// 店铺选中
shopCheckedTrue(state, index) {
const cartList = state.cartList;
cartList[index].shopChecked = true;
console.log(state.shopCheckedNum);
state.shopCheckedNum += 1; // 店铺数量+1
},
// 店铺取消选中
shopCheckedFalse(state, index) {
const cartList = state.cartList;
cartList[index].shopChecked = false;
state.shopCheckedNum -= 1;
},
// 全选
allCheckedTrue(state) {
state.allChecked = true;
},
// 取消全选
allCheckedFalse(state) {
state.allChecked = false;
},
因为方法涉及到一些逻辑判断,我把逻辑判断的部分都放在了actions里
// 商品状态
ProChecked({ state, commit }, { index, key }) {
const cartList = state.cartList;
// 这里要取反,因为此时的proChecked是点击按钮前的
!cartList[index].products[key].proChecked
? commit("proCheckedTrue", { index, key })
: commit("proCheckedFalse", { index, key });
// 商品全选,所选店铺选中
if (cartList[index].proCheckedNum === cartList[index].products.length) {
commit("shopCheckedTrue", index);
}
// 商品没全选 → 如果店铺选中改为未选中
// (不加这个判断条件的话 本来没选中的店铺也会执行shopCheckedFalse,导致商品选中数量会-1)
else if (cartList[index].shopChecked) {
commit("shopCheckedFalse", index);
}
// 判断店铺是否全选,改变全选按钮状态
if (state.shopCheckedNum === cartList.length) {
commit("allCheckedTrue");
} else {
commit("allCheckedFalse");
}
},
// 店铺选中状态
ShopChecked({ state, commit }, index) {
const cartList = state.cartList;
if (!cartList[index].shopChecked) {
// 让店铺选中 → 将当前店铺内未选中的商品改为选中
commit("shopCheckedTrue", index);
for (let k in cartList[index].products) {
if (!cartList[index].products[k].proChecked) {
commit("proCheckedTrue", { index, key: k });
}
}
} else {
// 店铺取消选中 → 将当前店铺内所有商品改为未选中
commit("shopCheckedFalse", index);
for (let k in cartList[index].products) {
commit("proCheckedFalse", { index, key: k });
}
}
if (state.shopCheckedNum === cartList.length) {
commit("allCheckedTrue");
} else {
commit("allCheckedFalse");
}
},
// 全选
AllChecked({ state, commit }) {
const cartList = state.cartList;
if (!state.allChecked) {
// 全选 → 所有未选中的店铺+商品全部选中
commit("allCheckedTrue");
for (let i in cartList) {
if (!cartList[i].shopChecked) {
commit("shopCheckedTrue", i);
}
for (let k in cartList[i].products) {
if (!cartList[i].products[k].proChecked) {
commit("proCheckedTrue", { index: i, key: k });
}
}
}
} else {
// 取消全选 → 所有店铺+商品取消选中
commit("allCheckedFalse");
for (let i in cartList) {
commit("shopCheckedFalse", i);
for (let k in cartList[i].products) {
commit("proCheckedFalse", { index: i, key: k });
}
}
}
},
最开始我是把这些代码都放在了三个方法里,这样写也能实现,但是看起来实在太乱了,而且不能追踪到具体是进行了什么操作。不想搞那么多方法的可以看看
// 单个商品选中
ProChecked(state, { index, key }) {
const cartList = state.cartList;
// 商品选中状态取反
cartList[index].products[key].proChecked =
!cartList[index].products[key].proChecked;
// 如果选中,选中数量+1,取消选中则-1
if (cartList[index].products[key].proChecked) {
cartList[index].proCheckedNum++;
} else {
cartList[index].proCheckedNum--;
}
// 如果商品全选,则店铺选中;否则店铺取消选中
if (cartList[index].proCheckedNum === cartList[index].products.length) {
cartList[index].shopChecked = true;
state.shopCheckedNum++;
} else if (cartList[index].shopChecked) {
cartList[index].shopChecked = false;
state.shopCheckedNum--;
}
// 判断店铺是否全选,改变全选按钮状态
if (state.shopCheckedNum === cartList.length) {
state.allChecked = true;
} else {
state.allChecked = false;
}
},
// 店铺选中
ShopChecked(state, index) {
const cartList = state.cartList;
// 取反
cartList[index].shopChecked = !cartList[index].shopChecked;
// 如果选中,选中数量+1,取消选中则-1
if (cartList[index].shopChecked) {
state.shopCheckedNum++;
} else {
state.shopCheckedNum--;
}
// 遍历当前店铺商品列表
for (let i in cartList[index].products) {
// 如果店铺被选中,所有商品改为选中状态,并且更改选中数量
if (cartList[index].shopChecked) {
cartList[index].products[i].proChecked = true;
cartList[index].proCheckedNum = cartList[index].products.length;
} else {
// 店铺取消选中,所有商品取消选中,选中数量为0
cartList[index].products[i].proChecked = false;
cartList[index].proCheckedNum = 0;
}
}
// 店铺列表全选,全选按钮选中
if (state.shopCheckedNum === cartList.length) {
state.allChecked = true;
} else {
state.allChecked = false;
}
},
// 全选
AllChecked(state) {
const cartList = state.cartList;
state.allChecked = !state.allChecked;
// 选中,全部店铺列表,商品选中,店铺,商品选中数量改变
for (let i in cartList) {
for (let k in cartList[i].products) {
if (state.allChecked) {
cartList[i].shopChecked = true;
state.shopCheckedNum = cartList.length;
cartList[i].products[k].proChecked = true;
cartList[i].proCheckedNum = cartList[i].products.length;
} else {
// 取消选中,所有店铺列表,商品取消选中,数量为0
cartList[i].shopChecked = false;
state.shopCheckedNum = 0;
cartList[i].products[k].proChecked = false;
cartList[i].proCheckedNum = 0;
}
}
}
},