最近有一個權限樹的需求,而且樹的結構比較深,想要實作,在不完全選中子節點後能夠擷取父節點的值,一并傳給後端。
不完全選中子節點後想要擷取父節點的值
如圖:選中【新增使用者】和【批量導入】時,想要把【使用者清單】和【使用者管理】的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}
/>
}
}
成功!