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;
}
相关推荐
王林不想说话5 分钟前
JavaScript 从入门到进阶:一篇覆盖核心知识、运行机制与工程实践
javascript
windliang6 分钟前
Claude Code 源码分析(十一):一段会话怎样保存、恢复与续写
前端·javascript·人工智能
小小尚@4 小时前
AE脚本-AE Actions v1.1.8 操作动作记录器
开发语言·前端·javascript·jupyter·postman
大家的林语冰4 小时前
👍 超越 ESLint,Oxc 优先采用 TypeScript 7,Rust 和 Go 梦幻联动!
前端·javascript·typescript
胡萝卜术6 小时前
在浏览器中跑 DeepSeek-R1:WebGPU 推理全流程深度解析
前端·javascript·面试
xiaominlaopodaren6 小时前
three.js地图数学基础(六):齐次坐标与矩阵
javascript·gis·three.js
AI砖家7 小时前
React Native 开发规范与完整流程指南
javascript·react native·react.js
小林ixn7 小时前
全栈项目实战:前端独立开发,不再傻等后端接口
前端·javascript·react.js
Asize7 小时前
前端接口工程:axios + mock,前端不再傻等后端
前端·javascript
张元清7 小时前
React useElementSize Hook:用 ResizeObserver 实时追踪元素宽高 (2026)
javascript·react.js