商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > el-table树形表格中复选框联动功能操作大全

el-table树形表格中复选框联动功能操作大全

  发布于2026-07-23 阅读(0)

扫一扫,手机访问

最终效果:

el-table树形表格中复选框联动功能操作大全

需求描述:

先说清楚两个核心需求点,这决定了后续实现的逻辑走向。

第一,父级复选框要能控制所有子级复选框。选中父级,子级全部跟着选中;取消父级,子级也全部取消。这个逻辑很直观,也好理解。

第二,反过来,子级复选框的状态变化不影响父级。也就是说,就算所有子级都选中了,父级也不会自动勾上;父级全选后,哪怕你把所有子级都取消勾选,父级的状态依然保持原样。这跟常见的父子联动逻辑不太一样,需要特别处理。

解决方法:

核心思路是给table列表数据加一个自定义标识(isCheck = false),通过复选框的点击事件来改变这个标识,再根据标识去控制复选框的实际选中状态。

先看基础代码结构,表格的配置没什么特别之处,关键点在于 @select@select-all 两个事件。

                                                                  

1. 初始化表格数据,给每个节点都加上 isCheck 标识,默认为 false。

    initCheckedBox() {      const initList = function(data) {        data.forEach(function(item) {          item.isCheck = false // 未选中          if (item.children) {            initList(item.children)          }        })        return data      }      this.rightCheckList = initList(this.tableList)    },

2. 先看全选逻辑。当用户点击表头全选复选框时触发的事件。

    // 当用户手动勾选全选 Checkbox 时触发的事件    selectAll(selection) {      if (!this.checkAll) {        this.checkAll = true        this.isAllChecked(this.rightCheckList, true)      } else {        this.checkAll = false        this.isAllChecked(this.rightCheckList, false)      }      const selectCheck = this.$getNodesIterative(this.rightCheckList, 'children', 'isCheck', true)      this.selectedRows = selectCheck.map(item => item.id)    },    // 是否全选中    isAllChecked(data, status) {      if (data === undefined) {        const imitData = []        imitData.push(data)      } else {        data.forEach(item => {          item.isCheck = item.parentId === 0 ? false : status          this.$refs.treeTable.toggleRowSelection(item, item.isCheck)          if (item.children) {            this.isAllChecked(item.children, status)          }        })      }    },

注意:checkAll 默认值为 false。

3. 再来看行级别的选择逻辑。这部分的处理要复杂一些,因为要根据节点的层级关系做不同操作。

     handleSelection(selection, row) {      row.isCheck = !row.isCheck      if(row.children.length === 0 && row.isCheck === true){        this.checkedParentRow(row, this.rightCheckList)      } else if(row.children.length === 0 && row.isCheck === false){        this.clearParentRow(row, this.rightCheckList)      } else if(row.children.length > 0 && row.isCheck === true){        this.isAllChecked(row.children, true)      } else if(row.children.length > 0 && row.isCheck === false){        this.isAllChecked(row.children, false)      }      const selectCheck = this.$getNodesIterative(this.rightCheckList, 'children', 'isCheck', true)      this.selectedRows = selectCheck.map(item => item.id)    },    // 选中子节点默认选中父节点,暂时不用,这段与需求不同,可不写。    // 如果有这个需求可写,并取消if隐藏代码    checkedParentRow(data, obj) {      for(var item in obj){        if(obj[item].id === data.parentId){          var every = obj[item].children.every(function(item) {            return item.isCheck === true          })          // if (every) {          //   obj[item].isCheck = true          //   this.$refs.treeTable.toggleRowSelection(obj[item], true)          // }        }      }    },    // 子节点都未被选中,父节点默认取消选中    clearParentRow(data, obj) {      const parentRow = this.$findTreeObjById(obj, 'id', data.parentId)      parentRow.isCheck = false      this.$refs.treeTable.toggleRowSelection(parentRow, false)    },

其中 this.$getNodesIterativethis.$findTreeObjById 被封装成了全局方法,具体实现如下:

/** * * @param {Array} treeList 树形数据 * @param {string} targetType 树形数据中所查找的键值 * @param {string} target 树形数据中所查找的值 * @returns */export function findTreeObjById(treeList, targetType, target) {  for (const item of treeList) {    // 匹配当前节点    if (item[targetType] === target) return item;    // 递归查找子节点    if (item.children && item.children.length > 0) {      const res = findTreeObjById(item.children, targetType, target);      if (res) return res;    }  }  return null; // 无匹配}/** * 提取树形结构中所有type为true的节点(迭代版,避免栈溢出) * @param {Array} tree 树形结构数组 * @param {string} childrenKey 子节点字段名 * @param {string} key 判断键值 * @param  flagValue 判断键值 * @returns {Array} 平级的符合条件的节点数组 */export function getNodesIterative(tree, childrenKey, key, flagValue) {  const result = [];  // 用栈存储待遍历的节点(初始为根节点数组)  const stack = [...tree];  while (stack.length > 0) {    const node = stack.pop(); // 栈顶取出节点(也可用shift()实现队列,效率略低)    // 筛选type为true的节点    if (node[key] === flagValue) {      result.push({ ...node });    }    // 子节点入栈(继续遍历)    if (Array.isArray(node[childrenKey])) {      stack.push(...node[childrenKey]);    }  }  return result;}export default {  findTreeObjById,  getNodesIterative}

总结:

这个功能在两个项目中都用到了,记录一下,顺便提醒自己:这段代码写了有两三年了,逻辑上没什么大问题,但代码结构上还有优化空间,后面记得重构一下。

本文转载于:https://www.jb51.net/javascript/356242fnb.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注