目录
1、代码分析
1.1 dom结构分析
购物车的组件结构主要由两部分组成:多选框部分( checkbox-group ) + 全选框部分( view )
1.2 全选控制反选
业务逻辑:
1、全选框(选中)——》 多选框(选中)、全选框(不选中)——》 多选框(不选中)
2、令复选框跟随全选框的状态变化——遍历数据,设置每条数据的 isChecked 状态
注意:因为无法直接操作数据,所以需要先行拷贝数据,再对其进行遍历(在本项目中,所有需要对数据进行遍历、筛选操作的步骤,都需要先拷贝数据)
allChecked(e){
console.log(e); //触发点击事件,拿到全选框的事件源对象
// 全选框: 状态为 true时,令其为 false,当状态为 false时,令其状态变为 true
if(this.data.isAllChecked){
// 遍历数据,令复选框的状态跟随全选框变化
// 拷贝数据、遍历数据
let goodslist=JSON.parse(JSON.stringify(this.data.goods))
goodslist.forEach(item=>item.isChecked=false)
this.setData({
isAllChecked:false,
goods:goodslist //重新渲染
})
}else{
let goodslist=JSON.parse(JSON.stringify(this.data.goods))
goodslist.forEach(item=>item.isChecked=true)
this.setData({
isAllChecked:true,
goods:goodslist
})
}
},
1.3 反选控制全选
业务逻辑:
1、多选框(全部选中)——》全选框(选中)
因为复选框有多个,全选框只有一个,所以多选框控制全选框被选中的前提是确定每一个多选框都被选中了 ,打印复选框的事件源对象,发现复选框有一 detail.value 属性,可显示 复选框为 true 的对象 / 数量。所以当 e.detail.value.length===this.data.goods.length 时,表示复选框都被选中了
2、多选框(有一不选中)——》全选框(不选中)
遍历数据( forEach ) 并 检查元素 ( includes ),如果 e.detail.value 中包含 数据id,则令该复选框的 isChecked=true,否则为 false
// 单选控制全选
changeCound(e) {
console.log(e);
let checkedArr = e.detail.value
if (checkedArr.length == this.data.goods.length) {
let goodsList = JSON.parse(JSON.stringify(this.data.goods))
goodsList.forEach(item => item.isChecked = true)
this.setData({
isAllChecked: true,
goods: goodsList
})
} else {
let goodsList = JSON.parse(JSON.stringify(this.data.goods))
goodsList.forEach(item => {
if (checkedArr.includes(item.id)) {
item.isChecked = true
} else {
item.isChecked = false
}
})
this.setData({
isAllChecked: false,
goods: goodsList
})
}
},
1.4、计算总价
通常用 reduce 来计算总价,其中 total 表示旧值,item表示新值,0为初始值
. reduce( ( total , item ) => { } , 0 )
// 计算总价
computedTotalPrice() {
let totalPrice = this.data.goods.reduce((total, item) => {
if (item.isChecked) {
return total + item.num * item.price
} else {
return total
}
}, 0)
this.setData({
totalPrice: totalPrice
})
},
1.4 加、减
// 加、减、删除
handle: function (e) {
let id = e.currentTarget.dataset.id
console.log(id);
var index = e.currentTarget.dataset.index
var val = `goods[${index}].num` //对数据对象 goods 中的 num 属性进行修改
let oldnum = this.data.goods.find(item => item.id == id).num //查找
console.log(oldnum);
// 减
if (e.currentTarget.dataset.name == "mulse") {
let newNum = oldnum - 1
if (newNum > 0) {
this.setData({
[val]: newNum
})
}else if(newNum == 0){
let goodsList = JSON.parse(JSON.stringify(this.data.goods))
let newGoodList=goodsList.filter(item=>item.id!==id)
this.setData({
goods:newGoodList
})
}
// 加
}else if(e.currentTarget.dataset.name=="add"){
let newnum=++oldnum
this.setData({
[val]:newnum
})
}
// 删除
else if (e.currentTarget.dataset.name == "del") {
let goodslist = JSON.parse(JSON.stringify(this.data.lists))
let newLists = goodslist.filter(item => item.id !== id)
this.setData({
lists: newLists
})
}
this.computedTotalPrice()
}
})
2、代码演示
index.wxml:
<checkbox-group bindchange="changeCound" class="top">
<view wx:for="{{goods}}" wx:key="id" class="checkbox">
<view class="chleft">
<checkbox value="{{item.id}}" checked="{{item.isChecked}}" class="cleft"></checkbox>
<image src="{{item.imgUrl}}" mode="" class="pic" />
</view>
<view class="Box">
<view class="box-left">
<text class="name">{{item.name}}</text>
<text class="price">¥{{item.price}}</text>
</view>
<view class="box-right">
<text bindtap="handle" data-id="{{item.id}}" data-name="mulse" data-index="{{index}}">-</text>
<text>{{item.num}}</text>
<text bindtap="handle" data-id="{{item.id}}" data-name="add" data-index="{{index}}">+</text>
<text bindtap="handle" class="del">x</text>
</view>
</view>
</view>
</checkbox-group>
<view class="bottom">
<view class="bottom-box" bindtap="allChecked">
<label>
<checkbox value="" checked="{{isAllChecked}}" />
<text>全选</text>
</label>
</view>
<view class="total">
{{totalPrice}} 元
</view>
</view>
index.scss
.top {
height:90vh;
overflow: auto;
.checkbox {
position: relative;
width: 100vw;
height: 100px;
border: 1px solid #eee;
display: flex;
flex-direction: row;
.chleft{
display: flex;
flex-direction: row;
align-content: center;
width: 41%;
.cleft {
margin-left: 10px;
margin-right: 10px;
line-height: 100px;
}
.pic {
width:80px;
height: 80px;
margin-top: 10px;
object-fit: cover;
}
}
.Box{
width: 59%;
height: 100%;
background-color: #fff;
.box-left{
position: relative;
width: 100%;
height: 50%;
text{
position: relative;
width:50px;
height: 20px;
margin-left: 10px;
}
.name{
position: absolute;
top:20rpx;
left:5rpx;
}
.price{
position: absolute;
top:20rpx;
right:5rpx;
text-align: left;
}
}
.box-right{
position: relative;
margin-top: 17px;
>text{
width: 20px;
margin-left: 10px;
font-weight: bolder;
}
.del{
position: absolute;
top:-2px;
right: 10px;
margin-left: 100px;
}
}
}
}
}
.bottom{
position: fixed;
bottom: 0;
left:0;
width: 100%;
height: 11vh;
box-shadow: 5px 5px 5px 5px rgb(204, 204, 204);
line-height: 11vh;
display: flex;
flex-direction: row;
.bottom-box{
width: 50%;
margin-left: 10px;
}
.total{
width: 50%;
text-align: right;
padding-right: 15px;
}
}
index.js
Page({
data: {
goods: [
{
id: '1',
name: '黄桃',
num: 10,
price: 10,
isChecked: false,
imgUrl: '/images/HT.jpg'
},
{
id: '2',
name: '西瓜',
num: 20,
price: 8,
isChecked: true,
imgUrl: '/images/XG.jpg'
},
{
id: '3',
name: '猕猴桃',
num: 6,
price: 12,
isChecked: false,
imgUrl: '/images/MHT.jpg'
}
],
isAllChecked: false,
totalPrice: 0
},
onLoad() {
this.computedTotalPrice()
},
// 单选控制全选
changeCound(e) {
console.log(e);
let checkedArr = e.detail.value
if (checkedArr.length == this.data.goods.length) {
let goodsList = JSON.parse(JSON.stringify(this.data.goods))
goodsList.forEach(item => item.isChecked = true)
this.setData({
isAllChecked: true,
goods: goodsList
})
} else {
let goodsList = JSON.parse(JSON.stringify(this.data.goods))
goodsList.forEach(item => {
if (checkedArr.includes(item.id)) {
item.isChecked = true
} else {
item.isChecked = false
}
})
this.setData({
isAllChecked: false,
goods: goodsList
})
}
this.computedTotalPrice()
},
// 全选控制单选
allChecked(e) {
if (this.data.isAllChecked) {
let goodsList = JSON.parse(JSON.stringify(this.data.goods))
goodsList.forEach(item => item.isChecked = false) //这里是赋值
this.setData({
isAllChecked: false,
goods: goodsList
})
} else {
let goodsList = JSON.parse(JSON.stringify(this.data.goods))
goodsList.forEach(item => item.isChecked = true) //这里是赋值
this.setData({
isAllChecked: true,
goods: goodsList
})
}
this.computedTotalPrice()
},
// 计算总价
computedTotalPrice() {
let totalPrice = this.data.goods.reduce((total, item) => {
if (item.isChecked) {
return total + item.num * item.price
} else {
return total
}
}, 0)
this.setData({
totalPrice: totalPrice
})
},
// 加、减、删除
handle: function (e) {
let id = e.currentTarget.dataset.id
console.log(id);
var index = e.currentTarget.dataset.index
var val = `goods[${index}].num`
let oldnum = this.data.goods.find(item => item.id == id).num
console.log(oldnum);
if (e.currentTarget.dataset.name == "mulse") {
let newNum = oldnum - 1
if (newNum > 0) {
this.setData({
[val]: newNum
})
}else if(newNum == 0){
let goodsList = JSON.parse(JSON.stringify(this.data.goods))
let newGoodList=goodsList.filter(item=>item.id!==id)
this.setData({
goods:newGoodList
})
}
}else if(e.currentTarget.dataset.name=="add"){
let newnum=++oldnum
this.setData({
[val]:newnum
})
}
this.computedTotalPrice()
}
})