提出需求
- 最近工作接到的需求,需要实现一个全选功能,但是这个全选是包括分页的
- 效果图如下
未选中
选中部分
点击全选
- 由于还有分页,下一页的选中状态不能确定
- 所以点击全选仍然是未确定状态
确定状态
什么时候为全选状态?
- 当所有的都被选上时才为全选
- 也就是
choiceList(选中的列表),等于数据总条数pageTotal - 那么就需要做一个选中记录了
什么时候为不确定状态?
- 只要有一个未选上就是未确定
- 也就是
choiceList(选中的列表),小于数据总条数pageTotal
什么时候为清空状态?
- 当
choiceList(选中的列表)的长度为0时
实现步骤
-
首先分为两个组件
- 子组件: 卡片组件
SonCard.vue - 父组件: 首页
Home.vue
- 子组件: 卡片组件
-
在父组件中定义一个空数组
choiceList(选中的列表), 子组件每次勾选都通过发送事件传递
// SonCard.vue
handleChange() {
this.$emit('choose', this.card.id); // id为卡片的唯一id
},
- 子组件的
<checkbox>绑定一个布尔值,通过判断唯一id是否包含在数组中,同时切页不会丢失已选中的状态
<!-- SonCard.vue -->
<el-checkbox :value="choiceList.includes(card.id)" @change="handleChange"/>
-
在父组件中监听
choose事件,并实现勾选和取消勾选时的逻辑- 若
id存在choiceList中,则为取消勾选状态,需将数组中id删除 - 反之则为勾选,需往数组中添加
id
- 若
<!-- Home.vue -->
<MaterialItemCard
v-for="item in cardList"
:key="item.id"
v-model="choiceList" // 此次使用v-model,子组件需要使用model项配置一下
:card="item"
@choose="changeChoose"
/>
// Home.vue
changeChoose(id) {
// 通过判断id是否存在数组中
const idIndex = this.choiceList.findIndex((num) => num === card.id);
if (idIndex <= -1) {
this.choiceList.push(card.id); // 不存在则往数组中添加
} else {
this.choiceList.splice(idIndex, 1); // 存在则删除对应的id
}
},
- 至此为止,单选功能已经实现,就算切换页数状态也不会丢失
- 首页中的
<checkbox>用于实现多选:
<!-- Home.vue -->
<el-checkbox
:value="checkAll" // 全选状态
:indeterminate="isIndeterminate" // 未确定状态
@change="handleCheckAllChange"
>全选</el-checkbox
>
computed: {
// 全选状态
checkAll() {
// 判断数据总数是否等于选中数组的长度
return this.page.total === this.choiceList.length;
},
// 未确定状态
isIndeterminate() {
// 选中数组的长度必须大于0且小于数据总数
return this.choiceList.length > 0 && this.choiceList.length < this.page.total;
},
},
- 当勾选全选框时,选中的是当前页的所有数据
handleCheckAllChange() {
if (this.checkAll) {
// 如果已经全选了,再点击一次则清空
this.choiceList = [];
} else if (this.cardList.every((item) => this.choiceList.includes(item.id))) {
// 如果当前页面已经全选
const ids = this.cardList.map((item) => item.id); // 过滤出id
// 再点击一次则把选中的id清除掉
this.choiceList = this.choiceList.filter((cid) => !ids.includes(cid));
} else {
// 否则把当前页面所有卡片的id都添加并去重,保证数量唯一
this.choiceList = [...new Set([...this.choiceList, ...this.cardList.map((material) => material.id)])];
}
}
- 至此分页多选功能已经实现