基于element-ui实现跨分页选择数据, 每页选中的数据互不干扰

  1. 封装
    基于element-ui (vue2版), 二次封装
/**
 *@author rik
 *@date 2023-04-01
 *@description 基于element-ui封装的跨页多选表格
 */
Vue.component('selector-table', {
  template: `
  <div style="width: 100%">
    <el-table border :data="tableData" style="width: 100%">
      <el-table-column min-width="180" align="center">
        <template #header="{ column, $index }">
          <div>
            <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange"></el-checkbox>
          </div>
        </template>
        <template #default="{ row, column, $index }">
          <div>
            <el-checkbox v-model="row[checkboxKey]" @change="handleCheckSingleChange(row)"></el-checkbox>
          </div>
        </template>
      </el-table-column>
      <slot></slot>
      <template #append>
        <slot name="append"></slot>
      </template>
    </el-table>
  </div>
  `,
  model: {
    prop: 'selectedArr',
    event: 'selectedArrChange'
  },
  props: {
    data: {
      type: Array,
      default: () => []
    },
    selectedArr: {
      type: Array,
      default: () => []
    },
    selectorkey: {
      type: String,
      default: 'id'
    }
  },
  data() {
    return {
      checkboxKey: Symbol(),
      tableData: [],
      isIndeterminate: false,
      checkAll: false
    };
  },
  watch: {
    data: {
      handler(val) {
        const valCopy = this.deepCopy(val);
        this.tableData = valCopy.map(cur => {
          cur[this.checkboxKey] = false;
          return cur;
        });
        this.tableData.forEach(cur => {
          if (this.selectedArr.some(_cur => _cur[this.selectorkey] === cur[this.selectorkey])) {
            cur[this.checkboxKey] = true;
          } else {
            cur[this.checkboxKey] = false;
          }
        });
        this.checkIsALLSelected() ? (this.checkAll = true) : (this.checkAll = false);
        this.patchBindObjNode('tableData');
      },
      immediate: true,
      deep: true
    },
    selectedArr: {
      handler(val) {
        this.tableData.forEach(cur => {
          if (val.some(_cur => _cur[this.selectorkey] === cur[this.selectorkey])) {
            cur[this.checkboxKey] = true;
          } else {
            cur[this.checkboxKey] = false;
          }
        });
        this.checkIsALLSelected() ? (this.checkAll = true) : (this.checkAll = false);
        this.patchBindObjNode('tableData');
      },
      immediate: true,
      deep: true
    }
  },
  methods: {
    handleCheckAllChange(val) {
      let arr = [];
      if (val) {
        this.checkAllTrue();
        arr = this.selectedArr.concat(this.deepCopy(this.tableData));
      } else {
        let deleteArr = [];
        this.checkAllFalse();
        this.tableData.forEach(cur => {
          if (this.selectedArr.some(_cur => _cur[this.selectorkey] === cur[this.selectorkey])) {
            deleteArr.push(cur[this.selectorkey]);
          }
        });
        arr = this.selectedArr.filter(cur => !deleteArr.some(_cur => _cur === cur[this.selectorkey]));
      }
      this.$emit('selectedArrChange', this.removeSymbolProperties(this.removeDuplicateKeyItem(arr, this.selectorkey)));
    },
    handleCheckSingleChange(row) {
      let arr = [];
      if (row[this.checkboxKey]) {
        arr = this.selectedArr.concat([this.deepCopy(row)]);
      } else {
        let deleteArr = [];
        this.selectedArr.forEach(cur => {
          if (cur[this.selectorkey] === row[this.selectorkey]) {
            deleteArr.push(cur[this.selectorkey]);
          }
        });
        arr = this.selectedArr.filter(cur => !deleteArr.some(_cur => _cur === cur[this.selectorkey]));
      }
      this.$emit('selectedArrChange', this.removeSymbolProperties(this.removeDuplicateKeyItem(arr, this.selectorkey)));
      this.checkIsALLSelected() ? (this.checkAll = true) : (this.checkAll = false);
    },
    //检查是否被全选
    checkIsALLSelected() {
      return !this.tableData.filter(cur => !cur[this.checkboxKey]).length;
    },
    //全选
    checkAllTrue() {
      this.tableData.forEach(cur => (cur[this.checkboxKey] = true));
    },
    //全不选
    checkAllFalse() {
      this.tableData.forEach(cur => (cur[this.checkboxKey] = false));
    },
    //如果表格数据的类型有 new Date() new Map() 等, 需要改造这个深拷贝函数
    deepCopy(obj, cache = []) {
      if (obj === null || typeof obj !== 'object') {
        return obj;
      }
      const hit = cache.filter(c => c.original === obj)[0];
      if (hit) {
        return hit.copy;
      }
      const copy = Array.isArray(obj) ? [] : {};
      cache.push({
        original: obj,
        copy
      });
      [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)].forEach(key => {
        copy[key] = this.deepCopy(obj[key], cache);
      });
      return copy;
    },
    //去重
    removeDuplicateKeyItem(arr, key) {
      return arr.reduce((acc, cur) => {
        if (!acc.some(obj => obj[key] === cur[key])) {
          acc.push(cur);
        }
        return acc;
      }, []);
    },
    //由于vue2不会代理symbol属性的原因, 手动更新依赖数据项的dom节点
    patchBindObjNode(obj) {
      this[obj] = this.deepCopy(this[obj]);
    },
    //去除symbol
    removeSymbolProperties(arr) {
      return arr.map(obj => {
        const newObj = {};
        Object.keys(obj).forEach(key => {
          newObj[key] = obj[key];
        });
        return newObj;
      });
    }
  }
});

  1. 笔者全局注册, 看官灵活运用
  2. 使用
    尽可能保留了原汁原味的el-table使用方法
  data: 表格数据, 和官网一样
  selectedArray: 双向绑定选中的数组
  @selected-arr-change: 点击复选框, 选中数组改变时触发事件
  <selector-table :data="tableData" v-model="selectedArray" @selected-arr-change="fun">
    <template #default>
      <el-table-column prop="date" label="日期" width="180"> </el-table-column>
      <el-table-column prop="name" label="姓名" width="180"> </el-table-column>
      <el-table-column prop="address" label="地址"></el-table-column>
      <el-table-column label="操作">
        <template #default="{ row, column, $index }">
          <el-button size="small" type="primary">编辑</el-button>
        </template>
      </el-table-column>
    </template>
    <template #append>
      <div style="text-align: right; padding: 16px">
        <el-pagination
          @current-change="handleCurrentChange"
          :current-page="1"
          :page-sizes="[10, 20, 50, 100]"
          :page-size="10"
          layout="total, sizes, prev, pager, next, jumper"
          :total="100"
        >
        </el-pagination>
      </div>
    </template>
  </selector-table>
  1. 核心代码和思路已经完善了, 可以直接用, 你也可以加以扩展
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值