天边孤鸿 發表於 2026-1-6 09:55:18

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

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">最终效果:</a></li><li><a href="#_label1">需求描述:</a></li><li><a href="#_label2">解决方法:</a></li><li><a href="#_label3">总结:</a></li></ul></div><p class="maodian"><a name="_label0"></a></p><h2>最终效果:</h2>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026010609550177.png" /></p>
<p class="maodian"><a name="_label1"></a></p><h2>需求描述:</h2>
<p>1.父级复选框可控制子级复选框状态:点击父级复选框选中或不选中时,子级复选框根据父级状态更新选中状态。</p>
<p>2.子级复选框不可控制父级复选框状态:子级复选框全选时,不会默认勾选父级复选框。父级全选后取消所有子级复选框,父级复选框状态不会改变。</p>
<p class="maodian"><a name="_label2"></a></p><h2>解决方法:</h2>
<blockquote><p>我的思路是给table列表数据添加一个标识 (isCheck = false),通过点击复选框改变标识,再通过标识来控制复选框选中状态。</p></blockquote>
<p>基础代码</p>
<div class="jb51code"><pre class="brush:js;">      &lt;el-table
          ref="treeTable"
          v-loading="loading"
          :data="tableList"
          row-key="id"
          stripe
          class="table_hei296"
          :expand-row-keys="expandRowKeys"
          @select="handleSelection"
          @select-all="selectAll"
          :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
      &gt;
          &lt;el-table-column type="selection" width="55" align="center" :selectable="handleSelectable"/&gt;
          &lt;el-table-column type="index" width="55" align="center" label="序号"/&gt;
          &lt;el-table-column prop="name" label="类名称" show-overflow-tooltip /&gt;
          &lt;el-table-column prop="code" label="编码" show-overflow-tooltip /&gt;
          &lt;el-table-column prop="groupType" label="组别" show-overflow-tooltip /&gt;
      &lt;/el-table&gt;</pre></div>
<p>1.初始化table列表数据。</p>
<div class="jb51code"><pre class="brush:js;">    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)
    },</pre></div>
<p>2.当用户手动勾选全选 Checkbox 时触发的事件</p>
<div class="jb51code"><pre class="brush:js;">    // 当用户手动勾选全选 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 =&gt; item.id)
    },
    // 是否全选中
    isAllChecked(data, status) {
      if (data === undefined) {
      const imitData = []
      imitData.push(data)
      } else {
      data.forEach(item =&gt; {
          item.isCheck = item.parentId === 0 ? false : status
          this.$refs.treeTable.toggleRowSelection(item, item.isCheck)
          if (item.children) {
            this.isAllChecked(item.children, status)
          }
      })
      }
    },</pre></div>
<blockquote><p>checkAll默认false</p></blockquote>
<p>3.当用户手动勾选数据行的 Checkbox 时触发的事件</p>
<div class="jb51code"><pre class="brush:js;">   handleSelection(selection, row) {
      row.isCheck = !row.isCheck
      if(row.children.length === 0 &amp;&amp; row.isCheck === true){
      this.checkedParentRow(row, this.rightCheckList)
      } else if(row.children.length === 0 &amp;&amp; row.isCheck === false){
      this.clearParentRow(row, this.rightCheckList)
      } else if(row.children.length &gt; 0 &amp;&amp; row.isCheck === true){
      this.isAllChecked(row.children, true)
      } else if(row.children.length &gt; 0 &amp;&amp; row.isCheck === false){
      this.isAllChecked(row.children, false)
      }
      const selectCheck = this.$getNodesIterative(this.rightCheckList, 'children', 'isCheck', true)
      this.selectedRows = selectCheck.map(item =&gt; item.id)
    },
    // 选中子节点默认选中父节点,暂时不用,这段与需求不同,可不写。
    // 如果有这个需求可写,并取消if隐藏代码
    checkedParentRow(data, obj) {
      for(var item in obj){
      if(obj.id === data.parentId){
          var every = obj.children.every(function(item) {
            return item.isCheck === true
          })
          // if (every) {
          //   obj.isCheck = true
          //   this.$refs.treeTable.toggleRowSelection(obj, true)
          // }
      }
      }
    },
    // 子节点都未被选中,父节点默认取消选中
    clearParentRow(data, obj) {
      const parentRow = this.$findTreeObjById(obj, 'id', data.parentId)
      parentRow.isCheck = false
      this.$refs.treeTable.toggleRowSelection(parentRow, false)
    },</pre></div>
<blockquote><p>this.$getNodesIterative与this.$findTreeObjById写成了全局方法,如下:</p></blockquote>
<div class="jb51code"><pre class="brush:js;">/**
*
* @param {Array} treeList 树形数据
* @param {string} targetType 树形数据中所查找的键值
* @param {string} target 树形数据中所查找的值
* @returns
*/
export function findTreeObjById(treeList, targetType, target) {
for (const item of treeList) {
    // 匹配当前节点
    if (item === target) return item;
    // 递归查找子节点
    if (item.children &amp;&amp; item.children.length &gt; 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 判断键值
* @paramflagValue 判断键值
* @returns {Array} 平级的符合条件的节点数组
*/
export function getNodesIterative(tree, childrenKey, key, flagValue) {
const result = [];
// 用栈存储待遍历的节点(初始为根节点数组)
const stack = [...tree];
while (stack.length &gt; 0) {
    const node = stack.pop(); // 栈顶取出节点(也可用shift()实现队列,效率略低)
    // 筛选type为true的节点
    if (node === flagValue) {
      result.push({ ...node });
    }
    // 子节点入栈(继续遍历)
    if (Array.isArray(node)) {
      stack.push(...node);
    }
}
return result;
}
export default {
findTreeObjById,
getNodesIterative
}</pre></div>
<p class="maodian"><a name="_label3"></a></p><h2>总结:</h2>
<p>这个功能两个项目中都用到了,所以记录下~</p>
<p>提醒自己:这段代码写了两三年了,没做优化,后面记得优化一下呀~</p>
頁: [1]
查看完整版本: el-table树形表格中复选框联动功能操作大全