最近在用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
也是極好的。優化