tree回显问题

问题描述:

1、el-tree 勾选反显,原本整个父子节点都勾选状态,新增一个子节点,因为父节点是全选状态,所以新增的子节点也呈勾选状态,实际是未勾选状态。

2、用的是default-checked-keys 回显

数据更新后,必须在 $nextTick 中调用 setCheckedKeys,这样才能确保树组件正确回显勾选状态。

解决思路:

问题 原因 解决方案
回显不生效 default-checked-keys 非响应式 使用 setCheckedKeys
设置时机不对 DOM 未渲染完成 包裹在 $nextTick 中
传了父节点 id 父节点会强制全选,并级联勾选所有子节点 只传叶子节点 id 给 setCheckedKeys
  • 核心逻辑
  • 先处理子节点,再根据子节点状态回推父节点
  • 只传叶子节点 id 给 setCheckedKeys,父节点状态由组件自动计算
  • markTreeChecked 返回的是树数据本身,不会影响 setCheckedKeys 的行为
    这样即使后端返回的数据中新增了子节点,父节点也能正确呈现半选状态。

html

javascript 复制代码
<el-tree
	:data="list"
	show-checkbox
	node-key="id"
	ref="tree"
	default-expand-all
	:props="{label: 'name',value: 'id'}"
></el-tree>

获取数据及回显调用(created 或 mounted)

javascript 复制代码
// 获取树的数据
getMenuTree()
  .then(res => {
    this.list = res.data.data;
    // 获取已勾选的数据id
    return getEchoData();
  })
  .then(res => {
    // 处理回显
    let menuIds = [];
    if (res.data.data.menuIds && res.data.data.menuIds.length > 0) {
      menuIds = res.data.data.menuIds.split(',');
    }
    
    // 根据返回的 menuIds 处理树数据,标记每个节点的选中状态(用于界面展示)
    this.markTreeChecked(this.list, menuIds);
    
    this.$nextTick(() => {
      if (this.$refs.tree) {
        // 只传叶子节点 id,避免父节点强制全选
        const leafIds = this.filterLeafIds(this.list);
        this.$refs.tree.setCheckedKeys(leafIds);
      }
    });
  });

methods

javascript 复制代码
// 递归标记树节点的选中状态
markTreeChecked(treeData, checkedIds) {
  treeData.forEach(node => {
    if (node.children && node.children.length > 0) {
      // 先处理子节点
      const childCheckedCount = this.markTreeChecked(node.children, checkedIds);
      
      // 根据子节点选中数量,计算当前父节点状态
      const allChecked = childCheckedCount === node.children.length;
      const noneChecked = childCheckedCount === 0;
      
      node.checked = allChecked;
      node.halfChecked = !allChecked && !noneChecked;
    } else {
      // 叶子节点:直接判断是否在选中列表中
      node.checked = checkedIds.includes(node.id);
    }
  });
}

// 收集所有选中的叶子节点 id
filterLeafIds(treeData) {
  const leafIds = [];
  
  const traverse = (nodes) => {
    nodes.forEach(node => {
      if (node.children && node.children.length > 0) {
        traverse(node.children);
      } else if (node.checked) {
        leafIds.push(node.id);
      }
    });
  };
  
  traverse(treeData);
  return leafIds;
}
相关推荐
不磕了还不行6 分钟前
用 Vue + Element UI 把元宝搜索的返回值做成“能点开检查的证据卡片”
前端·vue.js·ui
FRing0311 小时前
vue2干货总结2(v-bind、v-for、v-model、指令修饰符、v-bind操作class和style)
开发语言·前端·vue.js·vue2
幸运小猿11 小时前
模拟慢上传-处理超时重试image 丢失线上问题
前端·javascript·html
速易达网络14 小时前
ECharts 图表制作完全指南:从零到可视化实战
前端·javascript·echarts
徐小夕14 小时前
深度剖析 30k star 的编码 Agent DeepSeek-Reasonix:长会话 Token 成本直降 80%
前端·vue.js·github
paopaokaka_luck14 小时前
灾害应急物资管理系统(AI应急助手、Echarts可视化数据看板、捐赠入库联动、 物资全流程管理、库存变动追溯、灾情资讯与互动反馈、物资发放公示)
java·前端·javascript·spring boot·mysql·tomcat·echarts
kyriewen14 小时前
我验了 7 种 sticky 失效说法:3 种根本不成立
前端·javascript·程序员
我命由我1234516 小时前
Python 实用操作 - 文件操作(打开与关闭文件、读取文件、文件写入)
java·开发语言·前端·javascript·数据库·python·java-ee
Momo__16 小时前
你写的 import 重试,从来没生效过
前端·javascript·typescript
ruanno_top16 小时前
1 万行表格只渲染 18 行:虚拟滚动让我放弃了三个功能
vue.js