react+antdesign使用tree数选择组件,如何实现多组联动?
想要实现的是:一个员工可能存在多个分组,比如我在分组一中勾选张三,分组二、分组三中的张三也要同步勾选上,目前后端返回数据人员id相同,这样的话就导致树结构数据混乱出现脏数据,如果设置不同的key值又会出现点击第一个分组张三不生效,但是最后一个张三会被勾中
源于ChatGPT仅供参考
要实现多组联动,可以考虑使用 React 的状态管理来实现。首先需要在组件的 `state` 中定义一个用于存储选中节点的数组,然后在 TreeSelect 组件中通过 `value` 属性和 `onChange` 事件进行绑定。每次勾选或取消勾选一个节点时,都更新选中节点的数组,并根据当前选中的节点自动选中其它相关节点。
下面是一个简单的示例代码:
```jsx
import React, { useState } from 'react';
import { TreeSelect } from 'antd';
const treeData = [
{
title: '分组一',
value: 'group1',
children: [
{
title: '员工A',
value: 'employeeA',
},
{
title: '员工B',
value: 'employeeB',
},
],
},
{
title: '分组二',
value: 'group2',
children: [
{
title: '员工A',
value: 'employeeA',
},
{
title: '员工C',
value: 'employeeC',
},
],
},
];
function App() {
const [selectedKeys, setSelectedKeys] = useState([]);
function handleChange(value) {
setSelectedKeys(value);
}
function getRelatedKeys(key) {
const relatedKeys = [];
treeData.forEach(node => {
if (node.children && node.children.some(child => child.value === key)) {
relatedKeys.push(node.value);
}
});
return relatedKeys;
}
function handleCheck(checkedKeys, info) {
// 获取当前操作的节点
const currKey = info.node.props.value;
// 获取和当前节点相关的所有节点
const relatedKeys = getRelatedKeys(currKey);
// 生成最终选中的节点数组
const finalSelectedKeys = selectedKeys.filter(key => !relatedKeys.includes(key)).concat(checkedKeys);
// 更新选中节点数组状态
setSelectedKeys(finalSelectedKeys);
}
return (
<TreeSelect
treeData={treeData}
value={selectedKeys}
onChange={handleChange}
treeCheckable
showCheckedStrategy="SHOW_PARENT"
onCheck={handleCheck}
/>
);
}
export default App;
上述代码中,通过 useState
和 setSelectedKeys
定义了选中节点的数组 selectedKeys
,然后通过 value
属性和 onChange
事件将 TreeSelect 组件和 selectedKeys
绑定起来。在 handleCheck
函数中,先获取当前操作的节点和其它相关节点,然后根据当前选中的节点自动选中其它相关节点,并更新选中节点的数组状态。最终将 selectedKeys
数组作为 TreeSelect 组件的 value
属性值传入,就可以渲染出一个多组联动的 TreeSelect 组件了。
import { message, Tree } from 'antd';
import IconFont from '@/components/IconFont';
import React, { Fragment, PureComponent } from 'react';
import styles from './SelectTree.less';
import TreeOperate from "@/components/case/TreeOperate";
import { connect } from 'dva';
import { getQueryVariable } from '@/utils/fun'
const TreeNode = Tree.TreeNode;
@connect((state) => {
return { ...state.testcase };
})
class SelectTree extends PureComponent {
state = {
autoExpandParent: true,
projectsId:getQueryVariable('projectsId'),
};
componentDidMount() {
this.init()
this.props.onRef(this)
}
init = () => {
const projectsId = getQueryVariable('projectsId');
this.props.dispatch({
type: 'testcase/fetchCaseTree',
payload: { projectsId, menuType: 1, name: '' }
})
}
onCheck = (keys) => {
this.props.dispatch({
type: 'testcase/onCheck',
payload: { keys: keys.checked ? keys.checked : keys }
})
}
subKeys = (data, key, result) => {
data.forEach(v => {
if (v.children) {
this.subKeys(v.children, result);
}
})
return result;
}
//展开具体某个的方法
onExpand = expandedKeys => {
this.setState({
expandedKeys,
autoExpandParent: false,
});
};
deepTraversa = (node, nodeList = []) => {
if (node !== null) {
nodeList.push(node.key + '')
let children = node.children
for (let i = 0; i < children.length; i++) {
this.deepTraversa(children[i], nodeList)
}
}
return nodeList
}
//展开全部
onExpandAll = () => {
const { caseDate } = this.props;
const expandedKeys = [];
caseDate.forEach(item => {
expandedKeys.push(this.deepTraversa(item))
})
this.setState({
expandedKeys: expandedKeys.flat()
});
}
//收起全部
onExpandClose = () => {
this.setState({
expandedKeys: []
});
}
onDrop = ({ event, node, dragNode, dragNodesKeys}) =>{
console.log('拖拽')
}
render() {
const { caseDate, checkedKeys } = this.props;
const { expandedKeys, autoExpandParent } = this.state;
const IconFolder = ({ k }) => <IconFont type="icon-wenjianjia3" className={styles.icon_title} onClick={() => {
const subKeys = this.subKeys(caseDate, k, []);
this.onCheck({ checked: [...checkedKeys.checked.filter(v => subKeys.indexOf(v) === -1), ...subKeys.filter(v => checkedKeys.checked.indexOf(v) === -1)] })
}} />
const getData = (data, key = null) => {
const newData = data || []
return newData.map((item, index) => {
if (item.children && item.node_type === "menu") {
return (
<TreeNode title={<TreeOperate title={item.title} sourceData={item} ></TreeOperate>} selectable={false}
key={item.key}
icon={<IconFolder k={item.key} />} checkable={false}>
{getData(item.children, item.key)}
</TreeNode>
)
}
})
}
return (
<div style={{ overflowY: 'auto', height: '500px' }}>
<Tree checkable showLine showIcon blockNode draggable
className="hide-file-icon" checkStrictly
checkedKeys={checkedKeys.checked}
onCheck={this.onCheck}
onDrop={this.onDrop}
expandedKeys={expandedKeys}
onExpand={this.onExpand}
autoExpandParent={autoExpandParent}>
{getData(caseDate)}
</Tree>
</div>
)
}
}
export default SelectTree;