最近做一个小例子,主要是要实现一个类似淘宝购物车那种效果。主要的功能点有如下几点:
1最顶层的复选框,实现全选、全不选
2每个商家店铺前有一个复选框,实现全选(该店铺下的商品)全选、全不选
3 每个商家店铺里的商品在勾选的时候,逐一勾选直到全部勾选,当前商家店铺前的复选框会勾选,当此操作依次进行,所有商家店铺前的复选框都勾选时,最顶层的复选框实现全选,反之状态变更为-
再测试这个例子之前,官方的demo过于简单,所以对element-ui的checkbox、<el-checkbox-group>做了一些梳理:
(1)el-checkbox-group绑定的是数组,记录了当前组里当前勾选的集合。也就是el-checkbox-group的v-model的值实际就是当前组里当前勾选的集合
(2)el-checkbox-group 里v-model的值和 组里el-checkbox的关系如下:
<el-checkbox-group
v-model="item.checkedCities"
@change="(val)=>handleCheckedCitiesChange(val,item)"
>
<el-checkbox
v-for="(k,index) in item.list"
:key="index"
:label="k" >
{{k.city}}
</el-checkbox>
</el-checkbox-group>
这里:label="k"绑定的值的理解至关重要,如果label="k.id",那么el-checkbox-group里checkedCities就是所有组内元素id的集合,如果label="k.name",那么el-checkbox-group里checkedCities就是所有组内元素name的集合,如果label="k",那么el-checkbox-group里checkedCities就是所有组内元素的集合.
官方的说明文档中el-checkbox 的v-model的可选是是简单数据类型(number,string,boolean),实测绑定一个{}比如本例中的k也是可以的
(3)对于checkbox本身有两个属性要注意:
checked------------>true:勾选, fasle:不勾选
indeterminate----->true:横线: false :什么都没有
理解这两个状态非常重要。这里还有一点要注意的是:checkbox的checked属性为true的时候,必须让其indeterminate的状态为false。因为checkbox只能有一个样式控制。要么是-横线,要么是√。
接下来我们看看数据结构:
const lists=[
{
name:"华中",
checkGroupStatus:false,
isIndeterminate:false,
checkedCities:[],
list:[
{
checked:false,
city:"shanghai",
},
{
checked:false,
city:"tianjing",
},
{
checked:false,
city:"wuhan",
},
{
checked:false,
city:"shenyang",
},
{
checked:false,
city:"changsha",
}
]
},
{
name:"华东",
checkGroupStatus:false,
isIndeterminate:false,
checkedCities:[],
list:[
{
checked:false,
city:"langzhou",
},
{
checked:false,
city:"jingzho",
},
{
checked:false,
city:"hanzhong",
},
{
checked:false,
city:"wuxi",
},
{
checked:false,
city:"suzhou",
}
]
},
{
name:"华北",
checkGroupStatus:false,
isIndeterminate:false,
checkedCities:[],
list:[
{
checked:false,
city:"guangzhou",
},
{
checked:false,
city:"shenzhen",
},
{
checked:false,
city:"nanchang",
},
{
checked:false,
city:"chengdu",
},
{
checked:false,
city:"xian",
}
]
},
{
name:"华南",
checkGroupStatus:false,
isIndeterminate:false,
checkedCities:[],
list:[
{
checked:false,
city:"qingdao",
},
{
checked:false,
city:"xuzhou",
},
{
checked:false,
city:"yangzou",
},
{
checked:false,
city:"beijing",
},
{
checked:false,
city:"lasa",
}
]
}
]
再看看html结构:
<div>
<el-checkbox
v-model="checkAll"
:indeterminate="indeterminateAll"
@change="handleCheckAllChange"
>
全选
</el-checkbox>
</div>
<div class="group" v-for="item in testArr" :key="item.name">
<el-checkbox
v-model="item.checkGroupStatus"
:indeterminate="item.isIndeterminate"
@change="(val)=>handleCheckGroup(val,item)"
>
{{item.name}}
</el-checkbox>
<div >
<el-checkbox-group
v-model="item.checkedCities"
@change="(val)=>handleCheckedCitiesChange(val,item)"
>
<el-checkbox v-for="(k,index) in item.list" :key="index" :label="k" >{{k.city}}</el-checkbox>
</el-checkbox-group>
</div>
</div>
</div>
最后看看具体逻辑:
const handleCheckAllChange = () => {
if(checkAll.value){
testArr.forEach(group=>{
group.checkedCities=group.list;
group.checkGroupStatus=true
group.list.forEach(k=>k.checked=true)
})
}else{
testArr.forEach(group=>{
group.checkedCities=[];
group.checkGroupStatus=false
group.list.forEach(k=>k.checked=false)
})
}
}
//勾选group的复选项选择当前组
const handleCheckGroup=(val,group)=>{
if(val){
group.list.forEach(ele => {
group.checkedCities.push(ele)
})
}else{
if(!val){
group.checkedCities=[]
group.list.forEach(k=>k.checked=false)
}
}
//影响整体
checkAllStatus()
item.isIndeterminate= false;
}
const handleCheckedCitiesChange = (value,item) => {
item.checkGroupStatus = item.checkedCities.length === item.list.length?true:false;
item.isIndeterminate = item.checkedCities.length > 0 && item.checkedCities.length < item.list.length
//影响整体全选
checkAllStatus()
}
const checkAllStatus=()=>{
let isAll= testArr.every(group=>group.checkedCities.length==group.list.length)?true:false;
if(isAll){
checkAll.value=true
indeterminateAll.value=false
}else{
checkAll.value=false
indeterminateAll.value=true
}
}
以下是整体代码:
<template>
<div>
<div>
<el-checkbox
v-model="checkAll"
:indeterminate="indeterminateAll"
@change="handleCheckAllChange"
>
全选
</el-checkbox>
</div>
<div class="group" v-for="item in testArr" :key="item.name">
<el-checkbox
v-model="item.checkGroupStatus"
:indeterminate="item.isIndeterminate"
@change="(val)=>handleCheckGroup(val,item)"
>
{{item.name}}
</el-checkbox>
<div >
<el-checkbox-group
v-model="item.checkedCities"
@change="(val)=>handleCheckedCitiesChange(val,item)"
>
<el-checkbox v-for="(k,index) in item.list" :key="index" :label="k" >{{k.city}}</el-checkbox>
</el-checkbox-group>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue'
//全选状态控制
const checkAll=ref(false);
const indeterminateAll=ref(false);
const lists=[
{
name:"华中",
checkGroupStatus:false,
isIndeterminate:false,
checkedCities:[],
list:[
{
checked:false,
city:"shanghai",
},
{
checked:false,
city:"tianjing",
},
{
checked:false,
city:"wuhan",
},
{
checked:false,
city:"shenyang",
},
{
checked:false,
city:"changsha",
}
]
},
{
name:"华东",
checkGroupStatus:false,
isIndeterminate:false,
checkedCities:[],
list:[
{
checked:false,
city:"langzhou",
},
{
checked:false,
city:"jingzho",
},
{
checked:false,
city:"hanzhong",
},
{
checked:false,
city:"wuxi",
},
{
checked:false,
city:"suzhou",
}
]
},
{
name:"华北",
checkGroupStatus:false,
isIndeterminate:false,
checkedCities:[],
list:[
{
checked:false,
city:"guangzhou",
},
{
checked:false,
city:"shenzhen",
},
{
checked:false,
city:"nanchang",
},
{
checked:false,
city:"chengdu",
},
{
checked:false,
city:"xian",
}
]
},
{
name:"华南",
checkGroupStatus:false,
isIndeterminate:false,
checkedCities:[],
list:[
{
checked:false,
city:"qingdao",
},
{
checked:false,
city:"xuzhou",
},
{
checked:false,
city:"yangzou",
},
{
checked:false,
city:"beijing",
},
{
checked:false,
city:"lasa",
}
]
}
]
const testArr=reactive(lists)
const handleCheckAllChange = () => {
if(checkAll.value){
testArr.forEach(group=>{
group.checkedCities=group.list;
group.checkGroupStatus=true
group.list.forEach(k=>k.checked=true)
})
}else{
testArr.forEach(group=>{
group.checkedCities=[];
group.checkGroupStatus=false
group.list.forEach(k=>k.checked=false)
})
}
}
//勾选group的复选项选择当前组
const handleCheckGroup=(val,group)=>{
if(val){
group.list.forEach(ele => {
group.checkedCities.push(ele)
})
}else{
if(!val){
group.checkedCities=[]
group.list.forEach(k=>k.checked=false)
}
}
//影响整体
checkAllStatus()
group.isIndeterminate= false;
}
const handleCheckedCitiesChange = (value,item) => {
item.checkGroupStatus = item.checkedCities.length === item.list.length?true:false;
item.isIndeterminate = item.checkedCities.length > 0 && item.checkedCities.length < item.list.length
//影响整体全选
checkAllStatus()
}
const checkAllStatus=()=>{
let isAll= testArr.every(group=>group.checkedCities.length==group.list.length)?true:false;
if(isAll){
checkAll.value=true
indeterminateAll.value=false
}else{
checkAll.value=false
indeterminateAll.value=true
}
}
</script>
<style scoped>
</style>
提一点的是:真实的项目中对于每一个商品,勾选它呈现的状态后端是不可能给我们这个状态值的。对于每个店铺,勾选它时它的状态。也就是我们例子中的checkGroupStatus和isIndeterminate后端也不可能给我们。所以需要我在获取原始数据以后改造数据,添加这几个字段来记录其状态。这个也很简单。forEach循环给item,$set(item,"checkex",false),$set(group,"checkGroupStatus",false)即可。其他同理。