仿element自实现一个分页多选功能(Vue)

102 阅读2分钟

提出需求

  • 最近工作接到的需求,需要实现一个全选功能,但是这个全选是包括分页的
  • 效果图如下

未选中

image-20221103111835816.png

选中部分

image-20221103113659610.png

点击全选

  • 由于还有分页,下一页的选中状态不能确定
  • 所以点击全选仍然是未确定状态

image-20221103113906837.png

确定状态

什么时候为全选状态?

  • 当所有的都被选上时才为全选
  • 也就是 choiceList(选中的列表),等于数据总条数 pageTotal
  • 那么就需要做一个选中记录了

image-20221103114441866.png

什么时候为不确定状态?

  • 只要有一个未选上就是未确定
  • 也就是 choiceList(选中的列表),小于数据总条数 pageTotal

image-20221103114638650.png

什么时候为清空状态?

  • choiceList(选中的列表)的长度为0时

实现步骤

  1. 首先分为两个组件

    • 子组件: 卡片组件 SonCard.vue
    • 父组件: 首页 Home.vue
  2. 在父组件中定义一个空数组choiceList(选中的列表), 子组件每次勾选都通过发送事件传递

 // SonCard.vue
 handleChange() {
   this.$emit('choose', this.card.id); // id为卡片的唯一id
 },
  1. 子组件的 <checkbox>绑定一个布尔值,通过判断唯一 id 是否包含在数组中,同时切页不会丢失已选中的状态
 <!-- SonCard.vue -->
 <el-checkbox :value="choiceList.includes(card.id)" @change="handleChange"/>
  1. 在父组件中监听 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
   }
 },
  1. 至此为止,单选功能已经实现,就算切换页数状态也不会丢失
  2. 首页中的 <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;
   },
 },
  1. 当勾选全选框时,选中的是当前页的所有数据
 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)])];
   }
 }
  1. 至此分页多选功能已经实现