1、前提基础
- 掌握vue、element-ui相关前端知识,若有还没掌握的童鞋可以先去看我的vue全家桶一文:juejin.im/post/5bfe4a…。
2、业务场景描述
- 假设现在我们有一个人员列表,需要给每个人配置特定的权限来限制哪些人可以干些什么:
3、代码
- 新建AuthTree.vue页面:
"auth_tree">
"listData"
border
style="width: 100%;">
"ID" prop="id">
"姓名" prop="name">
"性别" prop="sex">
"权限配置">
"scope">
type="primary" size="mini" @click="opetation(scope.row.auth)">配置
"dialogVisible"
title="配置权限"
center
width="600px"
@close="closeDialog">
"dialog_main_content">
"tree"
:data="treeData"
:expand-on-click-node="false"
:show-checkbox="true"
node-key="id"
default-expand-all
@check="currentChecked"/>
"dialog_footer">
"cancel">取 消
type="primary" @click="confirm">确 定
复制代码
- 模拟数据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,这是在页面中引用封装好的组件。
"authTree"
:show-checkbox="true"
:tree-data="tableTreeData"
@currentChecked="currentChecked"/>
复制代码
这时如果我们使用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,记录几点的不同状态。
- 本文只是针对特定的场景的讲解,如遇到其它场景问题,欢迎留言一起讨论解决方案。