基於Ant Design的可編輯Tree的實現

JerryMissTom發表於2019-04-09

前言

最近在用Ant Design寫一個後臺,遇到的需求就是實現一個可動態增減和編輯子節點的Tree。GitHub上看了一圈,沒好用和合適的。索性就基於Ant Design中的Tree元件寫一個。實現的效果如下:

  • 可以增加子節點
  • 可以刪除子節點
  • 可以編輯子節點資訊
  • 可以取消編輯資訊

具體的效果圖如下:

screenshots

主要的就是藉助 TreeNodetitle 屬性,它的型別是string|ReactNode

正文

經過分析,一個節點的資料結構應該是

{
    value: 'Root', // 顯示的資訊
    defaultValue: 'Root', // 當某一節點進入編輯狀態,然後點選close按鈕,節點的資訊應該恢復原始狀態,
    key: '0-1', // 節點的Key,全域性唯一
    parentKey: '0', // 父節點的Key
    isEditable: false // 是否處於可編輯狀態
    children:[] // 子節點
}
複製程式碼

通過資料結構組裝TreeNode的程式碼如下:

state = {
    data: [
      {
        value: 'Root',
        defaultValue: 'Root',
        key: '0-1',
        parentKey: '0',
        isEditable: false
      }
    ]
  };


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>
    )
  }
複製程式碼

之後所有的增刪修改等都是修改this.state.data這個陣列中的資料,具體的看下程式碼就成,很簡單。 需要注意的一點就是,每次更新過底層資料,都需要呼叫 this.forceUpdate() 這個方法,否則介面不會更新。

最後優化這個元件的時候,遇到一個比較坑的。本來想是當在某節點上增加子節點時,父節點自動展開,程式碼邏輯上沒有問題,但是必須手動執行過一次展開或者搜尋的操作,所寫的邏輯才能生效。後來沒辦法,只能在生命週期函式中DOM載入完畢後主動觸發下:

componentDidMount() {
    this.onExpand([]); // 手動觸發,否則會遇到第一次新增子節點不展開的Bug
  }
複製程式碼

程式碼放在GitHub上了,地址是 react-editable-tree,歡迎有同樣需要的小夥伴參考,starfork 也是極好的。

相關文章