最近有一个权限树的需求,而且树的结构比较深,想要实现,在不完全选中子节点后能狗获取父节点的值,一并传给后端。
不完全选中子节点后想要获取父节点的值
如图:选中【新增用户】和【批量导入】时,想要把【用户列表】和【用户管理】的id也传给后端。
通过阅读API文档,onCheck
是复选框选中时触发,其中第二个参数是一个事件对象,他的返回值打印出来如下:
其中,有一个属性halfCheckedKeys
就是关联父节点的值。这样,我们可以轻松的拿到值了,和选中节点拼接起来一起传给后台就好了。
onCheck = (checkedKeysValue, e) => {
console.log('onCheck', checkedKeysValue);
console.log('e.halfCheckedKeys :>> ', e);
const checkedKeysResult = [...checkedKeysValue, ...e.halfCheckedKeys]
this.setState({
allCheckedId: checkedKeysResult
})
};
解决反写的时候,如果传入父节点 key,则子节点自动选中的问题
上面的处理在新建的时候没有问题,一旦到了编辑或者查看的时候,需要反写权限树,就会出问题,因为我们是受控组件,用到了checkedKeys
,选中复选框的树节点。请看API说明:
这样机会出现如果传入父节点 key,则子节点自动选中的情况。现在处理这个问题。
- 首先,在渲染树结构时把所有的叶子节点存在一个数组,叫
childArr
- 接着,利用后端接口返回的id数组(有父节点,有叶子节点)与
childArr
数组比较,取出相同的元素(可考虑使用lodash的_.intersection方法
) - 最后,将获得的新数组给
Tree
组件的checkedKeys
赋值
完整的权限树结构代码:
import React from 'react';
import { Tree } from 'antd';
let _ = require('lodash');
let childArr = [] // 存放所有子节点的数组
export default class CmpAuthTree extends React.Component {
constructor(props) {
super(props);
this.getData(this.props.treeData)
this.state = {
autoExpandParent: true,
expandedKeys: this.props.checkedList || [],
allCheckedId: [] // 传给后台的id数组
}
}
componentDidMount() {
this.initData()
}
componentDidUpdate(prevProps) {
this.updateData(prevProps)
}
initData = () => {
let uniqueChild = this.dataClean(this.props.checkedList)
this.setState({
checkedKeys: uniqueChild || []
})
}
updateData = (prevProps) => {
let uniqueChild = this.dataClean(this.props.checkedList)
if (prevProps.checkedList?.length !== this.props.checkedList?.length) {
this.setState({
expandedKeys: this.props.checkedList || [],
checkedKeys: uniqueChild || []
})
}
}
getData = (data) => {
data.map(res => {
res.title = res.name
res.key = res.menuId
if (res.children && res.children.length > 0) {
this.getData(res.children)
} else {
childArr.push(res.menuId)
}
})
return childArr
}
dataClean = (checkedList) => {
let allChildArr = this.getData(this.props.treeData)
let uniqueChild = _.intersection(checkedList, allChildArr)
return uniqueChild
}
onExpand = (expandedKeysValue) => {
console.log('onExpand', expandedKeysValue);
this.setState({
autoExpandParent: false,
expandedKeys: expandedKeysValue
})
};
onCheck = (checkedKeysValue, e) => {
console.log('onCheck', checkedKeysValue);
console.log('e.halfCheckedKeys :>> ', e);
const checkedKeysResult = [...checkedKeysValue, ...e.halfCheckedKeys]
let uniqueChild = this.dataClean(checkedKeysResult)
this.setState({
allCheckedId: checkedKeysResult,
checkedKeys: uniqueChild
})
};
getCheckedList() {
return this.state.allCheckedId
}
render() {
return <Tree
// defaultExpandAll
disabled={this.props.readOnly}
checkable
selectable={false}
onExpand={this.onExpand}
expandedKeys={this.state.expandedKeys}
autoExpandParent={this.state.autoExpandParent}
onCheck={this.onCheck}
checkedKeys={this.state.checkedKeys}
treeData={this.props.treeData}
/>
}
}
成功!