场景描述
项目中用到了elementUI的tree组件,角色跟菜单是一对多关联的。编辑一个角色时,可以选择多个菜单。修改角色的菜单功能需要进行回显,从后台获取数据在相对应的el-tree节点上打勾。
关键点说明
此解决方案不能适应所有情况。
使用此方案的前提:*将el-tree的属性 check-strictly 设置为 false(默认就是false)。目的是使父子节点相互关联。如果设置为true,此方案不适用。
思路
提交数据到后台时,需要使用tree的getHalfCheckedKeys和getCheckedKeys获取得到已勾选和半勾选的树节点id集合。因为开启了父子相互关联,所以提交的id集合中肯定会有叶子节点的id(这句是重点)。
回显时,从后台取到与某个角色关联的菜单的id集合中也一定会有叶子节点id。可以从集合中只取出叶子节点,调用el-tree的setCheckedKeys方法即可。
代码实现
在有网络的情况下,将全部代码复制到html中可查看效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- import CSS -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app">
<el-tree
:data="treeList"
show-checkbox
default-expand-all
node-key="id"
ref="tree"
highlight-current
:props="defaultProps">
</el-tree>
<el-divider></el-divider>
<div v-text="'半选节点id集合 : ' + halfCheckedKeys"></div>
<div v-text="'全选节点id集合 : ' + checkedKeys"></div>
<div v-text="'所有选中id集合 : ' + allChecked"></div>
<el-button @click="submit()">打印选中的id</el-button>
<el-divider></el-divider>
要回显的id集合:<input type="text" name="" id="" placeholder="以’,‘分割" v-model="toShowList"/>
<el-button @click="reShow()">回显</el-button>
</div>
</body>
<!-- import Vue before Element -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
<!-- import JavaScript -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script>
new Vue({
el: '#app',
data: function () {
return {
visible: false,
defaultProps: {
children: 'children',
label: 'name'
},
toShowList:'1,3,4,7',
halfCheckedKeys: [],
checkedKeys: [],
allChecked: [],
//list转为树形数据
treeList: this.treeDataTranslate(this.initData(), 'id', 'parentId', 'children'),
}
},
methods: {
//模拟请求后台数据
initData() {
let list = [];
//根,一级
list.push({id: 1, name: '1:根数据'})
//二级
list.push({id: 2, parentId: 1, name: '2:二级1'})
list.push({id: 3, parentId: 1, name: '3:二级2'})
list.push({id: 4, parentId: 1, name: '4:二级3'})
// 三级
list.push({id: 5, parentId: 2, name: '5:三级1-1'})
list.push({id: 6, parentId: 2, name: '6:三级1-2'})
list.push({id: 7, parentId: 3, name: '7:三级2-1'})
list.push({id: 8, parentId: 3, name: '8:三级2-2'})
list.push({id: 9, parentId: 4, name: '9:三级3-1'})
list.push({id: 10, parentId: 4, name: '10:三级3-2'})
//四级
list.push({id: 11, parentId: 5, name: '11:四级1-1-1'})
list.push({id: 12, parentId: 5, name: '12:四级1-1-2'})
return list
},
/**
* 树形数据转换
* @param {*} data list数据
* @param {*} id 主键ID
* @param {*} pid 上级ID
* @param childrenKey 子list数据的key
*/
treeDataTranslate(data, id = 'id', pid = 'parentId', childrenKey = 'children') {
let res = []
let temp = {}
for (let i = 0; i < data.length; i++) {
temp[data[i][id]] = data[i]
}
for (let k = 0; k < data.length; k++) {
if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) {
if (!temp[data[k][pid]][childrenKey]) {
temp[data[k][pid]][childrenKey] = []
}
temp[data[k][pid]][childrenKey].push(data[k])
} else {
res.push(data[k])
}
}
return res
},
// 获取数据,提交到后台
submit() {
this.halfCheckedKeys = this.$refs.tree.getHalfCheckedKeys()
this.checkedKeys = this.$refs.tree.getCheckedKeys()
this.allChecked = this.halfCheckedKeys.concat(this.checkedKeys)
// request请求 。。。。。。。。
},
//回显方法,应该放到mounted方法中执行调用,这里用按钮触发
reShow() {
// 所有数据的parentId数组
let allParentId = []
this.initData().forEach(ele => allParentId.push(ele.parentId))
//要勾选的节点id列表,数据应该来自后台
let checkedKeyArray = this.toShowList.split(',').map(ele => parseInt(ele))
//只需要叶子节点的id
let children = checkedKeyArray.filter(menuId => ! allParentId.includes(menuId) );
this.$refs.tree.setCheckedKeys(children)
}
}
})
</script>
</html>