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;
}
相关推荐
A黄俊辉A16 小时前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋17 小时前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁17 小时前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄18 小时前
JavaScript 隐式全局变量解析
javascript
honkun618 小时前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs199119 小时前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
雪芽蓝域zzs19 小时前
第26章:ECharts 自定义主题 + 页面一键切换主题(深色 / 浅色两套)
vue.js·echars
雪芽蓝域zzs19 小时前
第22章:ECharts 图表联动(多图表交互联动)
vue.js·echars
daols8820 小时前
vue 表格组件 vxe-table 实现虚拟滚动与无需滚动加载
vue.js·vxe-table
雪芽蓝域zzs20 小时前
第18章:ECharts 折线图 + 标记点、标记线,自定义 tooltip
vue.js·echars