ElementUI Tree组件的父子节点联动实现

实现效果分析

该权限树组件实现了以下的关键功能

  • 从后端获取角色权限并初始化树的选择状态
  • 父子节点联动选择
    • 父节点全选子节点也全选,父节点不选子节点也全不选,
    • 子节点选中一个父节点就要选中,子节点全都不选父节点可以单独选中
  • 获取全选和半选节点的权限码集合

核心代码解析

1.Tree组件模版
html 复制代码
<el-tree
  ref="preTreeRef"
  :data="permissionTree"
  show-checkbox
  node-key="code"
  highlight-current
  :expand-on-click-node="false"
  :props="defaultPermissionProps"
  :check-strictly="checkStrictly"
  @check="handleCheckChange"
>
</el-tree>

关键属性解析

  • node-key="code":使用权限码作为节点的唯一标识
  • :check-strictly="checkStrictly":禁用Element UI自带的父子关联,改为手动控制
  • @check="handleCheckChange":节点选择状态变化时触发自定义事件
2.初始化角色权限
js 复制代码
async getQueryRolePermission(id) {
  const roleId = id || this.addForm.roleId;
  const res = await queryRolePermissionCodes({ roleId });
  
  if (+res.code !== 200) {
    this.$message.error(res.msg || '请求失败');
    return;
  }
  
  const { permissionCodes } = res.data || [];
  const permissionCodesList = permissionCodes?.split(',') || [];
  
  this.$nextTick(() => {
    this.$refs.preTreeRef.setCheckedKeys(permissionCodesList, false);
    this.permissionCodes = permissionCodesList;
  });
}

关键属性解析

  • 使用$nextTick确保DOM更新完成后再操作树组件
  • setCheckedKeys第二个参数设为false避免触发check事件
  • 直接将权限码数组设置为选中状态
3.节点选择事件处理
js 复制代码
handleCheckChange(node, checkedStatus) {
  if (this.isHandling) return;
  this.isHandling = true;
  
  const checked = checkedStatus.checkedKeys.includes(node.code);
  
  if (checked) {
    // 选中节点时处理子节点和父节点
    if (node.children?.length) {
      this.checkAllChildren(node, true);
    }
    this.checkAllParents(node);
  } else {
    // 取消节点时处理子节点
    if (node.children?.length) {
      this.checkAllChildren(node, false);
    }
  }
  
  this.$nextTick(() => (this.isHandling = false));
  
  // 收集权限码
  const childCode = this.$refs?.preTreeRef?.getCheckedKeys() || [];
  const parentCode = this.$refs?.preTreeRef?.getHalfCheckedKeys() || [];
  this.permissionCodes = childCode.concat(parentCode);
}

逻辑解析

  • 使用isHandling标志位防止递归操作导致的死循环
  • 当节点被选中时:
    • 递归选中所有子节点
    • 递归向上选中所有父节点
  • 当节点被取消选中时:
    • 递归取消所有子节点
  • 收集全选和半选节点的权限码
4.递归操作子节点
js 复制代码
checkAllChildren(node, checked) {
  node.children.forEach(child => {
    this.$refs.preTreeRef.setChecked(child.code, checked);
    if (child.children) this.checkAllChildren(child, checked);
  });
}

逻辑解析

  • 递归操作子节点,使用setChecked方法设置每个节点的选中状态
5.递归操作父节点
js 复制代码
checkAllParents(node) {
  let parent = this.getParentNode(node);
  while (parent) {
    this.$refs.preTreeRef.setChecked(parent.code, true);
    parent = this.getParentNode(parent);
  }
}

逻辑解析

  • 从当前节点开始向上遍历父节点链
  • 将路径上的所有父节点设置为选中状态
  • 使用while循环代替递归,避免栈溢出风险
6. 父节点查找算法,返回目标节点的直接父节点
js 复制代码
getParentNode(node) {
  const findParent = (data, targetCode, parent) => {
    for (const item of data) {
      if (item.code === targetCode) return parent;
      if (item.children) {
        const found = findParent(item.children, targetCode, item);
        if (found) return found;
      }
    }
    return null;
  }
  return findParent(this.permissionTree, node.code, null);
}
相关推荐
A黄俊辉A2 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
honkun62 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19912 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
雪芽蓝域zzs2 天前
第26章:ECharts 自定义主题 + 页面一键切换主题(深色 / 浅色两套)
vue.js·echars
雪芽蓝域zzs2 天前
第22章:ECharts 图表联动(多图表交互联动)
vue.js·echars
daols882 天前
vue 表格组件 vxe-table 实现虚拟滚动与无需滚动加载
vue.js·vxe-table
雪芽蓝域zzs2 天前
第18章:ECharts 折线图 + 标记点、标记线,自定义 tooltip
vue.js·echars
雪芽蓝域zzs2 天前
第24章:ECharts 地图组件(基础行政区地图,若依 Vue3)
vue.js·echars
计算机毕设定制辅导-无忧学长2 天前
《基于Vue的流浪动物救助中心管理系统的设计与实现》
java·vue.js·spring boot·流浪动物救助中心管理系统
雪芽蓝域zzs2 天前
第25章:地图下钻交互(点击省份,切换到对应省份城市地图)
vue.js·echars