vue3+element-plus权限控制实现(el-tree父子级不关联情况处理)

简介: 后台管理系统常见的权限控制需求,这里讲button实现交互细节处理,取消选中子级menu/button,父级不关联取消;选中/取消父级catalog/menu,子级全部选中/取消;选中/取消部分子级menu/button,父级关联半选中状态(indeterminate=true);


@[TOC](文章目录)


---


# 前言

在开发后台管理系统的时候,用户的权限控制是一个常见的需求。这里需要探讨下按钮的级别的权限控制,以及实现中使用element-plus tree 组件的使用细节。


---

# 一、遇到的交互场景

基于原有的基础上实现按钮级别的权限控制,原有的如下图每一个菜单都有一个唯一ID,PID(父级ID),现在需要扩展的功能,就是添加一个button按钮控制,其中主要的细节交互:


1. **取消选中**子级menu/button,父级不关联取消;

2. **选中/取消**父级catalog/menu,子级全部选中/取消;

3. **选中/取消**部分子级menu/button,父级关联半选中状态(indeterminate=true);


其中我用的是el-tree 组件,我用button:xxx业务按钮;这样的方式来命名,后端也给了区分类型的字段type:catalog(目录),menu(菜单),button(按钮)。


![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/ba644e0f0bcd4ddf938d1bed15027e2a.png)

### el-tree 中 check-strictly 属性

el-tree 中 check-strictly 属性,为了实现**取消选中**子级menu/button,父级不关联取消,这里check-strictly设置为true;设置后点击父级也不关联子级选中了,用户用起来不方便,这里就需要我们自己处理

![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/43d3b00241164edfb7fc2853be9846c6.png)


# 二、处理父级的半选中以及选中交互

### el-tree

```html

<el-tree

           ref="treeRef"

           :check-strictly="true"

           :data="treeData"

           show-checkbox

           default-expand-all

           node-key="id"

           highlight-current

           :default-checked-keys="variable.roleForm.featureIds"

           :props="defaultProps"

           @check="hanleCheck"

           @check-change="checkChange"

         />

```

```js

const defaultProps = {

 children: 'children',

 label: function (treeData: any, treeNode: any) {

   return treeData?.name

 }

}

```

### check,check-change 事件

这里主要用的事件 check,check-change

![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/d38901b7e13f4eb9903ecc02e9cd6e5e.png)


```js

const hanleCheck = (data:any, node:any) => {

 console.log(data, node);

 // 获取当前节点是否被选中

 const isChecked = treeRef.value!.getNode(data).checked

 // 如果当前节点被选中,则遍历下级子节点并选中,如果当前节点取消选中,则遍历下级节点并取消

 if (isChecked) {

   // 判断该节点是否有下级节点,如果有那么遍历设置下级节点为选中

   data.children && data.children.length > 0 && setChildreChecked(data.children, true)

 } else {

   // 如果节点取消选中,则取消该节点下的子节点选中

   data.children && data.children.length > 0 && setChildreChecked(data.children, false)

 }

 function setChildreChecked(node:any, isChecked:boolean) {

   node.forEach((item:any) => {

     item.children && item.children.length > 0 && setChildreChecked(item.children, isChecked)

     // // 修改勾选状态

     treeRef.value!.setChecked(item.id, isChecked,false)

   })

 }

}


const checkChange = (data, checked, indeterminate) => {

     // console.log(data, checked, indeterminate);

     // 选中全部子节点,父节点也默认选中,但是子节点再次取消勾选或者全部子节点取消勾选也不会影响父节点勾选状态

     let checkNode = treeRef.value!.getNode(data)//获取当前节点

     // 勾选部分子节点,父节点变为半选状态

     if (checkNode.parent && checkNode.parent.childNodes.some(ele => ele.checked)) {

       checkNode.parent.indeterminate = true

     }

     // 勾选全部子节点,父节点变为全选状态

     if (checkNode.parent && checkNode.parent.childNodes.every(ele => ele.checked)) {

       checkNode.parent.checked = true

       checkNode.parent.indeterminate = false

     }

     // 如果取消所有第二节点的勾选状态,则第一层父节点也取消勾选

     if (checkNode.level == 2 && checkNode.parent.childNodes.every(ele => !ele.checked)) {

       checkNode.parent.checked = false

       checkNode.parent.indeterminate = false

     }

}


```

其中,上面用的

```js

     treeRef.value!.setChecked(item.id, isChecked,false)

```

看文档说第三个属性是是否要递归,我觉得是设置了true后,应该帮我递归选中/取消关联的节点,但没有生效,所以还是自己递归下;**(有大佬能指出是我的用法有问题吗?劳烦指出)**

![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/74bec0b2b8714f6698c6e75bf187bcb4.png)

### 编辑进来,父级的半选状态处理

上述方法实现后,我们就可以实现上述交互了,但这里要注意的一点,就是点击编辑进入的,父级的半选状态没有选中,也就是说 checkNode.parent.indeterminate 这个没有被设置为true;下面打个补丁。


```js

const editRole = async (row: any) => {

 const { permissionIds} = await detailApi({ id: row.id })

 await nextTick()

  setCheckedKeys(permissionIds)  // 返回用户的权限id后,根据id选中树节点


 permissionIds.forEach((id:any) => {

   const nodeData = treeRef.value!.getNode(id)  // 根据权限id,获取每个选中的树节点

   console.log('nodeData',nodeData)

   console.log('nodeData.parent?.id',nodeData.parent?.id)

   // 反显,上面setCheckedKeys后,如果父级没有选中,则把半选状态设置true

   if(nodeData?.parent?.id != 0 &&  !nodeData?.parent?.checked){

     nodeData.parent.indeterminate = true

   }

 });

}

```


---


# 总结

后台管理系统常见的权限控制需求,这里讲button实现交互细节处理,

1. **取消选中**子级menu/button,父级不关联取消;

2. **选中/取消**父级catalog/menu,子级全部选中/取消;

3. **选中/取消**部分子级menu/button,父级关联半选中状态(indeterminate=true);

下篇再补上button 的根据权限控制显示,用vue3 的指令实现,谢谢关注

相关文章
|
6天前
|
缓存 监控 UED
升级 Vue3 时,如何减少打包体积的增加?
升级 Vue3 时,如何减少打包体积的增加?
85 59
|
5天前
|
JavaScript
在vue3中(vite)引入unocss,安装配置unocss
在vue3中(vite)引入unocss,安装配置unocss
|
6天前
|
缓存 JavaScript 前端开发
「offer来了」从基础到进阶原理,从vue2到vue3,48个知识点保姆级带你巩固vuejs知识体系
该文章全面覆盖了Vue.js从基础知识到进阶原理的48个核心知识点,包括Vue CLI项目结构、组件生命周期、响应式原理、Composition API的使用等内容,并针对Vue 2与Vue 3的不同特性进行了详细对比与讲解。
「offer来了」从基础到进阶原理,从vue2到vue3,48个知识点保姆级带你巩固vuejs知识体系
|
6天前
|
API UED
如何实现Vue2项目升级Vue3?
如何实现Vue2项目升级Vue3?
13 1
|
6天前
|
API UED
升级 Vue3 后,项目的打包体积会有什么变化?
升级 Vue3 后,项目的打包体积会有什么变化?
92 57
|
7天前
|
JavaScript
vue组件中的插槽
本文介绍了Vue中组件的插槽使用,包括单个插槽和多个具名插槽的定义及在父组件中的使用方法,展示了如何通过插槽将父组件的内容插入到子组件的指定位置。
|
5天前
|
JavaScript
vue消息订阅与发布
vue消息订阅与发布
|
2天前
|
JavaScript
理解 Vue 的 setup 应用程序钩子
【10月更文挑战第3天】`setup` 函数是 Vue 3 中的新组件选项,在组件创建前调用,作为初始化逻辑的入口。它接收 `props` 和 `context` 两个参数,内部定义的变量和函数需通过 `return` 暴露给模板。`props` 包含父组件传入的属性,`context` 包含组件上下文信息。`setup` 可替代 `beforeCreate` 和 `created` 钩子,并提供类似 `data`、`computed` 和 `methods` 的功能,支持逻辑复用和 TypeScript 类型定义。
20 11
|
6天前
|
JavaScript 前端开发 IDE
Vue学习笔记5:用Vue的事件监听 实现数据更新的实时视图显示
Vue学习笔记5:用Vue的事件监听 实现数据更新的实时视图显示
|
6天前
|
JavaScript 前端开发 API
Vue学习笔记4:用reactive() 实现数据更新的实时视图显示
Vue学习笔记4:用reactive() 实现数据更新的实时视图显示
下一篇
无影云桌面