最近在用Ant Design写一个后台,遇到的需求就是实现一个可动态增减和编辑子节点的Tree。GitHub上看了一圈,没好用和合适的。索性就基于Ant Design中的Tree组件写一个。实现的效果以下:react
具体的效果图以下:git
主要的就是借助 TreeNode
的 title
属性,它的类型是string|ReactNode
。github
通过分析,一个节点的数据结构应该是数组
{
value: 'Root', // 显示的信息
defaultValue: 'Root', // 当某一节点进入编辑状态,而后点击close按钮,节点的信息应该恢复原始状态,
key: '0-1', // 节点的Key,全局惟一
parentKey: '0', // 父节点的Key
isEditable: false // 是否处于可编辑状态
children:[] // 子节点
}
复制代码
经过数据结构组装TreeNode
的代码以下:bash
data= [
{
value: 'Root',
defaultValue: 'Root',
key: '0-1',
parentKey: '0',
isEditable: false
}
];
state={
data: this.data
}
renderTreeNodes = data => data.map((item) => {
if (item.isEditable) { // 编辑状态下
item.title = (
<div>
<input value={item.value}
onChange={(e) => this.onChange(e, item.key)}/>
<Icon type='close' style={{marginLeft:10}} onClick={() => this.onClose(item.key, item.defaultValue)}/>
<Icon type='check' style={{marginLeft:10}} onClick={() => this.onSave(item.key)}/>
</div>
);
} else {
item.title = (
<div>
<span>
{item.value}
</span>
<Icon style={{ marginLeft: 10 }} type='edit' onClick={() => this.onEdit(item.key)} />
<Icon style={{ marginLeft: 10 }} type='plus' onClick={() => this.onAdd(item.key)} />
{item.parentKey === '0' ? null : (<Icon style={{ marginLeft: 10 }} type='minus' onClick={() => this.onDelete(item.key)} />)} // 根节点没有删除按钮
</div>
)
}
if (item.children) {
return (
<TreeNode title={item.title} key={item.key} dataRef={item}>
{this.renderTreeNodes(item.children)}
</TreeNode>
);
}
return <TreeNode {...item}/>;
})
...
// 渲染界面
render() {
return (
<div>
<Tree>
{this.renderTreeNodes(this.state.data)}
</Tree>
</div>
)
}
复制代码
以后全部的增删修改等都是先修改data
这个数组中的数据,而后使用this.setState({ data: this.data })
更新界面,具体的看下代码就成,很简单。数据结构
最后优化这个组件的时候,遇到一个比较坑的。原本想是当在某节点上增长子节点时,父节点自动展开,代码逻辑上没有问题,可是必须手动执行过一次展开或者搜索的操做,所写的逻辑才能生效。后来没办法,只能在生命周期函数中DOM加载完毕后主动触发下:函数
componentDidMount() {
this.onExpand([]); // 手动触发,不然会遇到第一次添加子节点不展开的Bug
}
复制代码
代码放在GitHub上了,地址是 react-editable-tree,欢迎有一样须要的小伙伴参考,star
和fork
也是极好的。优化