1.效果图
2.官方组件的示例不是很全面,而且右边不是树形的;直接上源码,我的是ts的语法,参考的原文章是js语法
//组件代码
import React, { useState,forwardRef,useImperativeHandle } from 'react'
import { Transfer, Tree,Modal } from 'antd'
import { DataNode } from 'antd/es/tree'
import './chooseUserTransfer.less'
const AuthorizationModal = (props: any, ref: any) => {
const [targetKeys, setTargetKeys] = useState<any>([])
const [rightTreeData, setRightTreeData] = useState([])
const [treeData,setTreeData]=useState([])
const generateTree = (treeNodes: DataNode[] = [], checkedKeys: string[] = []): DataNode[] =>
treeNodes.map(({ children, ...props }:any) => ({
...props,
disabled: checkedKeys.includes(props.key as string),
children: generateTree(children, checkedKeys),
}))
const dealCheckboxSeleted = ({ node, onItemSelect, onItemSelectAll }:any, direction:any) => {
let {
checked,
halfCheckedKeys,
node: { key, children },
} = node
// 勾选的是父节点
if (children?.length > 0) {
let keys: any[] = []
let temp = []
if (direction === 'left') {
let state = false
if (rightTreeData.length > 0) {
rightTreeData?.map((item:any) => {
if (item?.childCompanies?.length > 0 && (item.key == key)) {
temp = item.childCompanies.filter((v:any) => !item.childCompanies.some(((t:any) => t.key === v.key)))
temp?.forEach((child:any) => {
keys.push(child.key)
})
} else {
state = true
}
})
} else {
state = true
}
if (state) {
children?.forEach((child:any) => {
keys.push(child.key)
})
}
onItemSelectAll([...keys, key], checked)
}
if (direction === 'right') {
children?.forEach((child:any) => {
keys.push(child.key)
})
onItemSelectAll([...keys], checked)
}
} else {
// 勾选的是子节点
if (!checked) {
// 查找该元素的父元素
let parentKeys = []
parentKeys = [halfCheckedKeys?.[0]] || []
if (parentKeys[0] == undefined) {
// 当一级下的二级全部取消勾选,一级也取消勾选
treeData.forEach((tree:any) => {
if (tree.children) {
tree.children?.forEach((child:any) => {
if (child?.key === key) {
parentKeys.push(tree?.key)
}
})
}
})
}
onItemSelectAll([...parentKeys, key], checked)
} else {
let parentKey:any =''
treeData.forEach((tree:any) => {
if (tree?.children) {
tree.children?.forEach((child:any) => {
if (child?.key === key) {
parentKey = tree?.key
}
})
}
})
if (!halfCheckedKeys?.includes(parentKey) && parentKey != '') {
onItemSelectAll([key, parentKey], checked)
} else {
onItemSelect(key, checked)
}
}
}
}
// modal组件
const [type, setType] = useState(1);//1选择用户2选择用户组
const [isModalOpen, setIsModalOpen] = useState(false);
const handleOk = () => {
let result:any = []
rightTreeData.forEach((ele:any)=>{
result.push({
key:ele.key,
title:ele.title,
})
ele.children.forEach((eles:any)=>{
result.push({
key:eles.key,
title:eles.title,
})
})
})
result=result.filter((ele: any) =>targetKeys.includes(ele.key)&&ele.key.split('_').length>2)
props.onChildData(type, result)
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
useImperativeHandle(ref, () => ({
// changeVal 就是暴露给父组件的方法
// changeVal: () => {
// setIsModalOpen(true);
// }
showModal
}));
const showModal = (type: number, data: any, rightData: []) => {
setIsModalOpen(true);
setType(type)
setTreeData(data)
let keyArr:any=[]
rightData.forEach((ele:any)=>{
keyArr.push(ele.key)
ele.children.forEach((eles:any)=>{
keyArr.push(eles.key)
})
})
setTargetKeys(keyArr)
setRightTreeData(rightData)
};
const TreeTransfer = ({ dataSource, targetKeys, ...restProps }:any) => {
const transferDataSource:any = []
const dataSourceData = dataSource
let rightTreeDataResult = [...rightTreeData]
function flatten(list = []) {
list.forEach((item:any) => {
transferDataSource.push(item)
flatten(item.children)
})
}
flatten(dataSource)
return (
<Transfer
{...restProps}
targetKeys={targetKeys}
dataSource={transferDataSource}
className="tree-transfer"
showSearch
showSelectAll={true}
render={item => item.title}
rowKey={record => record.key}
// 搜索功能逻辑
onSearch={(dir, val) => {
let data = (dir === 'left' ? dataSourceData : rightTreeData)
// 1.先遍历二级,过滤出搜索对应的数据;
// 2.如果二级有数据,过滤出二级的companyName和一级的companyName
// 3.最后把一级不符合搜索对应的值过滤
const newDeptList = data?.map((item:any) => {
item = Object.assign({}, item)
if (item.children) {
item.children = item.children?.filter((res:any) => (res.title.indexOf(val) > -1))
}
return item
}).filter((item:any) => {
if (item.children?.length > 0 || val.length == 0) {
item = Object.assign({}, item)
item.children?.filter((e:any) => (
e.title.indexOf(val) > -1 ? '' : item.title.indexOf(val) > -1
))
} else {
item = item.title.indexOf(val) > -1
}
return item
})
if (dir === 'left') {
dataSource = newDeptList
}
if (dir === 'right') {
rightTreeDataResult = newDeptList
}
}}
>
{({ direction, onItemSelect, onItemSelectAll, selectedKeys }) => {
if (direction === 'left') {
const checkedKeys = [...selectedKeys, ...targetKeys]
return (
<Tree
blockNode
checkable
checkedKeys={checkedKeys}
defaultExpandedKeys={checkedKeys}
treeData={generateTree(dataSource, targetKeys)}
fieldNames={{ title: 'title', key: 'key', children: 'children' }}
onCheck={(_, node) => {
dealCheckboxSeleted({ node, onItemSelect, onItemSelectAll }, direction)
}}
onSelect={(_, node) => {
dealCheckboxSeleted({ node, onItemSelect, onItemSelectAll }, direction)
}}
/>
)
}
if (direction === 'right') {
//defaultExpandAll 默认展开全部
const checkedKeys = [...selectedKeys]
return (
<Tree
blockNode
checkable
checkedKeys={checkedKeys}
treeData={rightTreeDataResult}
fieldNames={{ title: 'title', key: 'key', children: 'children' }}
onCheck={(_, node) => {
dealCheckboxSeleted({ node, onItemSelect, onItemSelectAll }, direction)
}}
onSelect={(_, node) => {
dealCheckboxSeleted({ node, onItemSelect, onItemSelectAll }, direction)
}}
/>
)
}
}}
</Transfer>
)
}
/**
* 改变右边tree数据
* @param {*右边tree需要处理的keys集合} keys
* @param {*0-删除以上的keys 1-新增以上的keys} type
*/
const getRightTreeData = (keys:any, type:any) => {
let arr:any = [...rightTreeData]
if (keys?.length > 0) {
keys.forEach((key:any) => {
treeData.forEach((data:any) => {
if (key === data.key) {
// 勾选的是父节点,查看右侧是否有勾选对象
let index = arr.findIndex((i:any) => {
return i.key === key
})
if (type === 1) {
if (index === -1) {
arr.push(data)
} else if (index > -1 && arr?.[index]?.children?.length < data?.children?.length) {
// 先选择子项再勾选该父级时,传过来的keys是 ['0-1-0','0-1'],此时第一次循环已经将该父级放到arr中,
// 再遍历0-1时,需要先删除再将全部的children复制
arr.splice(index, 1)
arr.push(data)
}
} else if (type === 0) {
if (index > -1) {
arr.splice(index, 1)
}
}
} else {
// 勾选的是子节点
// 左侧数据处理
let selectedParentKey = '' //选定的父项id
let selectedObj:any = {} //选定对象
if (data?.children?.length > 0) {
data.children.forEach((child:any) => {
if (key === child.key) {
selectedParentKey = data.key
selectedObj = child
}
})
}
// 右侧数据处理
if (Object.keys(selectedObj)?.length > 0) {
let newData:any = {}
// 查看右侧是否有选中子项的父项
let index = arr.findIndex((item:any) => {
return item.key === selectedParentKey
})
if (index > -1) {
// 右侧已有选中子项的父项,selectedIndex查看右侧子项是否有勾选对象
let oldChildArr = [...arr[index].children]
let selectedIndex = oldChildArr?.findIndex(o => {
return o.key === selectedObj.key
})
if (selectedIndex === -1 && type === 1) {
arr[index].children.push(selectedObj)
}
if (selectedIndex > -1 && type === 0) {
arr[index].children.splice(selectedIndex, 1)
if (arr[index].children?.length === 0) {
arr.splice(index, 1)
}
}
} else {
// 右侧没有选中子项的父项
if (type === 1) {
newData = { ...data }
newData.children = []
newData.children.push(selectedObj)
arr.push(newData)
} else if (type === 0) {
arr = []
}
}
}
}
})
})
setRightTreeData(arr)
}
}
// 左右移动按钮
const onChange = (keys:any, direction:any, moveKeys:any) => {
let changeArrType = 1 // 0-删除 1-新增
if (direction == 'left') {
changeArrType = 0
if (keys.length > 0) {
treeData.forEach((item:any) => {
let index = keys.indexOf(item.key)
if (index > -1 && item.children?.length > 0) {
item.children?.forEach((v:any) => {
if (moveKeys.includes(v.key)) {
keys.splice(index, 1)
}
})
}
})
}
}
setTargetKeys(keys)
let keysList = changeArrType === 1 ? keys : moveKeys
getRightTreeData(keysList, changeArrType)
};
return <Modal width={600} title={type == 1 ? '选择用户' : '选择设备'} open={isModalOpen} onOk={handleOk} onCancel={handleCancel}>
<TreeTransfer dataSource={treeData} targetKeys={targetKeys} onChange={onChange} /> </Modal>
}
export default forwardRef(AuthorizationModal)
3.如何引入使用代码
import ChooseUserTreeTransfer from "../../components/Common/Add/chooseUserTransfer"
//方法
const childRefUser = useRef<any>(null)
const eventClick=()=>{
childRefUser.current.showModal()
}
const getChildDataUser = (type: number, data: any) => {
}
//组件使用
<ChooseUserTreeTransfer ref={childRefUser} onChildData={getChildDataUser}></ChooseUserTreeTransfer>
备注
参考地址:https://blog.csdn.net/weixin_49581008/article/details/128953065