以下是这个组件中需要实现的功能
- 树的节点拖拽并且只能是平级与平级之间
- 节点hover出现新增删除编辑设置
引入树组件
import { Tree } from 'antd';
const { TreeNode } = Tree;
构造树的假数据
this.state = {
treeData: [{
title: '获奖行为',
key: '获奖行为',
children: [{
title: '奥赛',
key: '奥赛'
}, {
title: '运动会',
key: '运动会'
}]
}, {
title: '学习行为',
key: '学习行为',
children: [{
title: '下乡',
key: '下乡'
}]
}],
nodeId: '',
nodeName: '',
selectedKeys: []
}
render 树组件
<Tree
className="draggable-tree"
draggable
blockNode
defaultExpandAll
onSelect={this.onSelect}
selectedKeys={this.state.selectedKeys}
onDragEnter={this.onDragEnter}
onDrop={this.onDrop}
>
{this.loop(this.state.treeData, '')}
</Tree>
递归树节点 loop方法
title类型为string|ReactNode
由于需要hover显示出设置所以在title里直接写
loop(data, parentId) {
return data.map(item => {
if (item.children && item.children.length) {
return (
<TreeNode key={item.key} title={
<div className='tree-item'>
<span className='tree-label' title={item.title}>{item.title}</span>
<span className='icon-box'>
设置
</span>
<div className='tree-tools-list'>
<ul>
<li onClick={this.addNode.bind(this, item.key, item.title)}>添加</li>
<li onClick={this.editNode.bind(this, item.key, '')}>修改分类名称</li>
<li onClick={this.deleteNode.bind(this, item.key)}>删除分类</li>
</ul>
</div>
</div>
}>
{this.loop(item.children, item.key)}
</TreeNode>
);
}
return <TreeNode key={item.key} title={
<div className='tree-item'>
<span className='tree-label' title={item.title}>{item.title}</span>
<span className='icon-box'>
设置
</span>
<div className='tree-tools-list'>
<ul>
<li onClick={this.editNode.bind(this, item.key, parentId)}>修改分类名称</li>
<li onClick={this.deleteNode.bind(this, item.key)}>删除分类</li>
</ul>
</div>
</div>
} />;
});
}
拖拽时
onDrop(info) {
const dropKey = info.node.props.eventKey; //拖拽落下的值
const dragKey = info.dragNode.props.eventKey; //被拖拽的值
const dropPos = info.node.props.pos.split('-'); //拖拽落下的位置 最外层到最里层
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
const loop = (data, key, callback) => {
data.forEach((item, index, arr) => {
if (item.key === key) {
return callback(item, index, arr);
}
if (item.children) {
return loop(item.children, key, callback);
}
});
};
const data = [...this.state.treeData];
// Find dragObject
let dragObj;
let drag = info.dragNode.props.pos;
let dragLength = info.dragNode.props.pos.split('-').length;
let drop = info.node.props.pos;
let dropLength = info.node.props.pos.split('-').length;
if (!info.dropToGap) {
//平级与平级之间不能拖拽为子级
if((dropPosition==0&&dropPos.length==3)||(dropPosition==0&&dropPos.length==2&&dragLength==2)){
}else{
loop(data, dragKey, (item, index, arr) => {
arr.splice(index, 1);
dragObj = item;
});
loop(data, dropKey, item => {
item.children = item.children || [];
// where to insert 示例添加到尾部,可以是随意位置
item.children.push(dragObj);
});
}
// Drop on the content
} else if (
(info.node.props.children || []).length > 0 && // Has children
info.node.props.expanded && // Is expanded
dropPosition === 1 // On the bottom gap
) {
loop(data, dragKey, (item, index, arr) => {
arr.splice(index, 1);
dragObj = item;
});
loop(data, dropKey, item => {
item.children = item.children || [];
// where to insert 示例添加到头部,可以是随意位置
item.children.unshift(dragObj);
});
}
else {
//一级不能拖拽为二级、二级子级
if((dragLength==3&&dropLength==2)||(dragLength==2&&dropLength==3)){
return;
}
loop(data, dragKey, (item, index, arr) => {
arr.splice(index, 1);
dragObj = item;
});
let ar;
let i;
loop(data, dropKey, (item, index, arr) => {
ar = arr;
i = index;
});
if (dropPosition === -1) {
ar.splice(i, 0, dragObj);
} else {
ar.splice(i + 1, 0, dragObj);
}
}
this.setState({
treeData: data,
});
}
判断length是否等于2或者是等于3,是因为树节点生成时默认一级为0-0,二级为0-0-0,split后length就是2或者3了。
目前项目中树只有两级所以采取这种曲线救国的方式,空了再研究适用于所有级的平级拖拽。