el-tree(包含多层级子节点) 结合 el-table(分页表格)实现双向绑定 (支持表格全选当前页 支持表格分页全选 需要后端配合)

 效果图如下:

// 树配置项
defaultProps: {
   children: 'children',
   label: 'label',
   disabled: "disabled"
}
          
          <el-tree
            ref="tree"
            node-key="id"
            :data="treeData"
            :props="defaultProps"
            :show-checkbox="true"
            :default-expand-all="true"
            :expand-on-click-node="false"
            :highlight-current="true"
            empty-text=""
            @node-click="handleNodeClick"
            @check="handleCheckboxClick">
            <slot class="custom-tree-node" v-slot="{ node, data }">
              <span>{{ node.label }}</span>
            </slot>
          </el-tree>
<el-table ref="multipleTable"
                    :data="tableData"
                    :cell-style="row"
                    :header-cell-style="header"
                    tooltip-effect="light"
                    @select="handleSelectionChange"
                    @select-all="handleSelectionAllChange">
            <el-table-column type='selection' />
            <template v-for="(i, index) in tableOptions">
              <el-table-column :key="index" :prop="i.prop" :label="i.label" :width="i.width" :show-overflow-tooltip="true">
                <template v-slot="scope">
                  <div v-html="formatValue(i.prop, scope.row)"></div>
                </template>
              </el-table-column>
            </template>
          </el-table>
// 选中树节点事件
    handleNodeClick(row) {
      if (!row.id || this.queryParams.parentId === row.id) {
        return
      }

      this.queryParams.pageNum = 1;
      this.queryParams.parentId = row.id;

      this.getRegionInfoById();
    }

// 选中树节点查询事件
    async getRegionInfoById () {
      this.loading = true;
      const res = await getRegionByInfo( this.queryParams );

      if ( res.code !== 200 ) {
        return
      }
      this.total = res.data.data.total;
      this.tableData = res.data.data.list;
      this.queryParams.superiorsId = res.data.superiorsId;
      this.queryParams.juniorsId = res.data.juniorsId;
      this.loading = false;

      this.$nextTick(this.toggleSelection);
    }

// 操作分页表格勾选状态
    toggleSelection() {
      this.tableData.forEach(row => {
        // 如果当前id不存在于集合中 (例如:我选择其他目录数据 选中当前目录没选择数据 初始化状态)
        if (!this.checkedNodes.has(row.parentId)) {
          this.$refs.multipleTable.clearSelection();
          return
        }

        const nodes = this.checkedNodes.get(row.parentId);

        // 代表全选
        if (nodes.isCheckAll && !nodes.check.length && !nodes.del.length) {
          this.$refs.multipleTable.toggleRowSelection(row, true);
          return
        }

        // 代表单选
        if (nodes.check.length && nodes.check.includes(row.regionId)) {
          this.$refs.multipleTable.toggleRowSelection(row, true);
          return
        }

        // 代表全选后单选取消
        if (nodes.del.length && !nodes.del.includes(row.regionId)) {
          this.$refs.multipleTable.toggleRowSelection(row, true);
          return
        }

        this.$refs.multipleTable.toggleRowSelection(row, false);
      })
    }

// 全选树形事件
    handleCheckboxClick(node, data) {
      if (!node.size) {
        return
      }

      // 如果row中没有children 表示是子节点 允许set到map中
      if (!node.children) {
        this.checkedNodes.set(node.id, { isCheckAll: true, check: [], del: [] });
      } else {
        const ds = (array) => {
          if (!!array.children) {

            ds(array.children);
            return
          }

          if (Object.prototype.toString.call(array) === '[object Object]') {
            this.checkedNodes.set(array.id, { isCheckAll: true, check: [], del: [] });
          }

          if (Object.prototype.toString.call(array) === '[object Array]') {
            array.forEach(row => this.checkedNodes.set(row.id, { isCheckAll: true, check: [], del: [] }));
          }
        }

        node.children.forEach(ds)

      }

      // 将map集合所有key在data.checkedKeys中对比 如果不存在 代表取消勾选 在map中删除掉取消的key
      const differentElements = Array.from(this.checkedNodes.keys()).filter(element => !data.checkedKeys.includes(element));
      differentElements.forEach(element => this.checkedNodes.delete(element));

      // 是否在父子节点中存在
      if (this.queryParams.superiorsId.includes(node.id) || this.queryParams.juniorsId.includes(node.id)) {
        this.$nextTick(this.toggleSelection);
      }
    }

// 单选表格数据
    async handleSelectionChange(selection, row) {
      if (!row.parentId || !row.regionId) {
        return
      }

      // 声明变量获取储存后的map集合
      const selectRegionIdArr = this.checkedNodes;

      // 如果集合不存在当前 key 就初始化一个
      if (!selectRegionIdArr.has(row.parentId)) {
        selectRegionIdArr.set(row.parentId, { isCheckAll: false, check: [], del: [] });
      }

      // 集合中找到当前文件夹的 values
      const values = selectRegionIdArr.get(row.parentId);

      // 判断选中的人员中是否存在重复的
      const checkIndex = values.check.indexOf(row.regionId);
      const delIndex = values.del.indexOf(row.regionId);

      // 执行单选以及取消单选操作
      !values.isCheckAll ? checkIndex < 0 ? values.check.push(row.regionId) : values.check.splice(checkIndex, 1)
        : delIndex < 0 ? values.del.push(row.regionId) : values.del.splice(delIndex, 1);

      const nodes = this.$refs.tree.getNode(row.parentId);
      await this.updateTreeDataSelection(nodes, values);
    }

 // 全选表格当前页数据
    handleSelectionAllChange(selection) {
      if (!!selection.length) {
        selection.forEach(row => this.updateNodeState(row, true));
      } else {
        this.tableData.forEach(row => this.updateNodeState(row, false));
      }
    },
    async updateNodeState(row, b) {
      const treeInstance = this.$refs.tree; // 获取 el-tree 实例
      const checkNodes = this.checkedNodes; // 获取 map 集合

      if (!checkNodes.has(row.parentId)) {
        checkNodes.set(row.parentId, { isCheckAll: false, check: [], del: [] });
      }

      const values = checkNodes.get(row.parentId);

      if (values) {
        // 判断选中的点位中是否存在重复的
        const checkIndex = values.check.indexOf(row.regionId);
        const delIndex = values.del.indexOf(row.regionId);
        if (!values.isCheckAll) {
          // 单选 全选当前页
          if (checkIndex < 0 && b) {
            values.check.push(row.regionId);
          }

          if (checkIndex >= 0 && !b) {
            values.check.splice(checkIndex, 1);
          }
        } else {
          // 全选 全选当前页
          if (delIndex >= 0 && b) {
            values.del.splice(delIndex, 1);
          }

          if (delIndex < 0 && !b) {
            values.del.push(row.regionId);
          }
        }
      }

      const nodes = treeInstance.getNode(row.parentId);

      await this.updateTreeDataSelection(nodes, values);
    }

// 操作树结构勾选状态以及改变集合状态
    updateTreeDataSelection(nodes, values) {
      // 代表该目录是全选状态
      if (!values.check.length && !values.del.length && values.isCheckAll) {
        // 给与当前节点在树中的勾选状态
        this.$refs.tree.setChecked(nodes, true);
        // 当前节点在树的勾选状态
        // nodes.checked = true;
        // 当前节点在树的的不明确状态
        nodes.indeterminate = false;
        // 当前节点在集合中勾选状态
        values.isCheckAll = true;
        return
      }

      // 代表该目录没有任何勾选状态
      if (!values.check.length && !values.del.length && !values.isCheckAll) {
        // 给与当前节点在树中的勾选状态
        this.$refs.tree.setChecked(nodes, false);
        // 当前节点在树的勾选状态
        // nodes.checked = false;
        // 当前节点在树的的不明确状态
        nodes.indeterminate = false;
        // 当前节点在集合中勾选状态
        values.isCheckAll = false;
        return
      }

      // 代表该目录是全选状态
      if (values.check.length === nodes.data.size && !values.del.length) {
        // 给与当前节点在树中的勾选状态
        this.$refs.tree.setChecked(nodes, true);
        // 当前节点在树的勾选状态
        // nodes.checked = true;
        // 当前节点在树的的不明确状态
        nodes.indeterminate = false;
        // 当前节点在集合中勾选状态
        values.isCheckAll = true;
        // 清空当前节点在集合中的选中数组
        values.check.splice(0);
        return
      }

      // 代表该目录是半选状态
      if (values.check.length < nodes.data.size && !values.del.length) {
        // 给与当前节点在树中的勾选状态
        this.$refs.tree.setChecked(nodes, true);
        // 当前节点在树的勾选状态
        nodes.checked = true;
        // 当前节点在树的的不明确状态
        nodes.indeterminate = true;
        // 当前节点在集合中勾选状态
        values.isCheckAll = false;
        return
      }

      // 代表该目录是全选后单选取消状态
      if (values.del.length === nodes.data.size && !values.check.length) {
        // 给与当前节点在树中的勾选状态
        this.$refs.tree.setChecked(nodes, false);
        // 当前节点在树的勾选状态
        // nodes.checked = false;
        // 当前节点在树的的不明确状态
        nodes.indeterminate = false;
        // 当前节点在集合中勾选状态
        values.isCheckAll = false;
        // 清空当前节点在集合中的选中数组
        values.del.splice(0);
        return
      }

      // 代表该目录是全选后单选取消完
      if (values.del.length < nodes.data.size && !values.check.length) {
        // 给与当前节点在树中的勾选状态
        this.$refs.tree.setChecked(nodes, true);
        // 当前节点在树的勾选状态
        nodes.checked = true;
        // 当前节点在树的的不明确状态
        nodes.indeterminate = true;
        // 当前节点在集合中勾选状态
        values.isCheckAll = true;
      }
    }

map集合 key是存在children的区域id

全选区域下面所有的数据 那么 check 以及 del都是为空

全选数据后 单选取消 check为空 del不为空

单选数据 check不为空 del为空

有错误的地方 请大佬指教

您好,针对您的问题,您可以参考以下步骤来实现el-table分页组件支持全选: 1. 在el-table头部添加一个checkbox,用来全选当前页的数据,代码如下: ```html <el-table-column type="selection" width="55"></el-table-column> ``` 2. 在el-table上添加v-model,用来绑定当前选中的数据,代码如下: ```html <el-table v-model="selectedData" :data="tableData" :pagination="pagination"> ``` 3. 在el-pagination上添加@size-change和@current-change事件,用来监听分页变化事件,代码如下: ```html <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="pagination.currentPage" :page-sizes="[10, 20, 30, 50]" :page-size.sync="pagination.pageSize" :total="total"> </el-pagination> ``` 4. 在methods中添加handleSizeChange和handleCurrentChange方法,用来处理分页变化事件,代码如下: ```javascript methods: { handleSizeChange (val) { this.pagination.pageSize = val this.loadTableData() }, handleCurrentChange (val) { this.pagination.currentPage = val this.loadTableData() }, loadTableData () { // 加载当前页数据 } } ``` 5. 在computed中添加selectedData和total属性,分别用来计算当前选中的数据和数据总数,代码如下: ```javascript computed: { selectedData () { return this.tableData.filter(item => this.selection.includes(item.id)) }, total () { return this.tableData.length } } ``` 这样就可以实现el-table分页组件支持全选了,希望对您有所帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值