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);
}
相关推荐
ℋᙚᵐⁱᒻᵉ鲸落4 小时前
移动端滑动手势冲突:overflow: auto导致外层横向滑动失效
前端·javascript·css·vue.js·html
用户500937683903911 小时前
热敏小票 Web 打印:我在 58/80mm 上折腾的两周
前端·vue.js
snow@li19 小时前
服务器运维:Alibaba Cloud Linux 4 LTS・Vue前端 Java 后端 K3S 部署 CICD 目录规范清单
linux·前端·vue.js
honkun619 小时前
vue 表格组件 vxe-table 实实现专业记账凭证编辑表格与自动汇总
前端·javascript·vue.js
web打印社区1 天前
网页静默打印热敏小票:从 HTML 到出纸的完整指南
前端·javascript·vue.js·electron·pdf·html
parade岁月1 天前
为了给表格加虚拟滚动而选了 vxe-table?也可以考虑下这个
前端·vue.js
鹏多多2 天前
PC 网站接入微信登录,这 10 个坑我替你踩完了!
前端·javascript·vue.js
染指11102 天前
103.RAG-LLamaIndex后端rag问答-聊天接口
前端·javascript·vue.js·人工智能
单线程_012 天前
从案例分析 Vue3 Tokenizer+Parser 源码三
前端·javascript·vue.js
jay神2 天前
【计算机毕业设计】基于SpringBoot的程序教学辅助系统
java·前端·vue.js·spring boot·后端·毕业设计·课程设计