1、前提基础
- 掌握vue、element-ui相关前端知识,若有还没掌握的童鞋可以先去看我的vue全家桶一文:。
2、业务场景描述
- 假设现在我们有一个人员列表,需要给每个人配置特定的权限来限制哪些人可以干些什么:
3、代码
- 新建AuthTree.vue页面:
复制代码配置
- 模拟数据data部分:
data() { return { listData: [ { id: 1, name: 'syz', sex: '男', auth: [1, 2] }, { id: 2, name: 'lyy', sex: '女', auth: [11, 21] }, { id: 3, name: 'yf', sex: '男', auth: [211, 212] }, { id: 4, name: 'xkl', sex: '女', auth: [211] }, { id: 5, name: 'txl', sex: '女', auth: [221] } ], dialogVisible: false, treeData: [ { id: 1, label: '一级 1', children: [ { id: 11, label: '二级 1-1' }, { id: 12, label: '二级 1-2' } ] }, { id: 2, label: '一级 2', children: [ { id: 21, label: '二级 2-1', children: [ { id: 211, label: '三级 2-1-1' }, { id: 212, label: '三级 2-1-2' } ] }, { id: 22, label: '二级 2-2', children: [ { id: 221, label: '三级 2-2-1' } ] } ] } ] } }复制代码
4、 问题描述
问题一:
- 点击配置opetation(scope.row.auth),需要弹出弹框并设置默认权限,这里我们通过id为依据来勾选,这是需要设置依据node-key="id"
opetation (auth) { this.dialogVisible = true this.$refs.tree.setCheckedKeys(auth) }复制代码
这时候将会报以下错误:
vue.esm.js?efeb:591 [Vue warn]: Error in event handler for "click": "TypeError: Cannot read property 'setCheckedKeys' of undefined"相信很多人遇到过这个问题,这是因为this.dialogVisible = true时并没有立即更新dom,而是等整个逻辑执行完后再一次新渲染,因此此时的弹框并未渲染,在dom树中是不存在的,this.$refs.tree is undefined的所以setCheckedKeys肯定也是undefined。解决方法: this.$nextTick(),this.$nextTick()会在dom更新之后在执行回调:opetation (auth) { this.dialogVisible = true this.$nextTick(function() { this.$refs.tree.setCheckedKeys(auth) })}复制代码
到这里每次打开弹框的时候都会获取最新的角色权限并勾选。
问题二:
- 获取节点数据后,当父节点被勾选时,所有的子节点全部被勾选,而实际上很多时候只有部分子节点被勾选。
- 通过check的方法获取节点的信息:
currentChecked(data, currentChecked) { const { checkedNodes, halfCheckedNodes } = currentChecked console.log(checkedNodes, halfCheckedNodes) }复制代码
- check的方法,有两个参数,该节点所对应的对象、树目前的选中状态对象(含checkedNodes、checkedKeys、halfCheckedNodes、halfCheckedKeys 四个属性)。树节点的状态有三种,选中,部分选中,未选中。checkedNodes表示当前选中的节点,halfCheckedNodes表示部分选中(只可能存在于父节点,父节点下有部分子节点被选中)。
- 这里提供一个解决思路,记录选中节点的状态:
currentChecked(data, currentChecked) { let auth = [] const { checkedNodes, halfCheckedNodes } = currentChecked halfCheckedNodes.length && halfCheckedNodes.forEach(({ id }) => { auth.push({ id, type: 2 }) }) checkedNodes.length && checkedNodes.forEach(({ id }) => { auth.push({ id, type: 1 }) }) // api 将auth数据保存至后台 }复制代码
- 修改opetation方法和listData数据,根据type过滤,只设置全部选中的节点(type=1),父节点会根据子节点的情况自动勾选。
auth: [ { id: 1, type:1 }]复制代码
opetation (auth) { this.dialogVisible = true const arr = [] auth.length &&auth.map(({ id, type }) => { type === 1 && arr.push(id) }) this.$nextTick(function() { this.$refs.tree.setCheckedKeys(arr) })}复制代码
问题三:
- 当我们将el-tree封装成一个公用的组件的时候,比如叫auth-tree,这是在页面中引用封装好的组件。
复制代码
这时如果我们使用this.$refs.authTree.setCheckedKeys(auth) 仍然会报错:
vue.esm.js?efeb:591 [Vue warn]: Error in event handler for "click": "TypeError: Cannot read property 'setCheckedKeys' of undefined"复制代码
解决办法:在父组件中:
click() { this.$refs.authTree.setCheckedKeys(auth) }复制代码
在组件中添加setCheckedKeys方法:
setCheckedKeys(auth) { this.$refs.tree.setCheckedKeys(auth) }复制代码
5、 总结
- node-key="id", 设置节点状态的依据。
- this.$nextTick()弹框打开后的回调。
- setCheckedKeys()必须是通过节点本身的ref来直接。
- checkedNodes, halfCheckedNodes,记录几点的不同状态。
- 本文只是针对特定的场景的讲解,如遇到其它场景问题,欢迎留言一起讨论解决方案。