這次在做了一個樹形的展示功能,誰知產品意猶未盡,找我談話:
PD: 什麼?只有展開收起功能?這怎麼行,咱們最基礎的要支援編輯,支援搜尋,如果可以的話還可以做個反向定位...
YY: 你咋不早說?需求檔案上也沒有啊...
PD: 你看誰家檔案一次寫到位的?哪家的PD不加需求?
YY: 話是這樣說,可事情不是這麼做的...
PD: 哎呀,別杵著浪費時間了,快去做吧!
YY: ...
以上故事純屬虛構,如有雷同請評論區留言...
樹形資料在開發中算是比較常見了,資料夾、組織架構、生物分類、國家地區等等,世間萬物的大多數結構都是樹形結構。使用樹控制元件可以完整展現其中的層級關係,並具有展開收起選擇等互動功能。
專案倉庫:https://github.com/speakice/editable-tree
能實現以上功能的方法庫和元件有很多種,這裡只講其中一種,都是Ant Design的元件:
import { Tree, Dropdown, Menu, Tabs, Input, Switch } from 'antd';import shortid from 'shortid';複製程式碼
操作樹行資料,最重要的前提是要有一個趁手的遞迴方法:
/** * 如果需要修改tree,action就返回修改後的item, 不修改就不返回 */export const deepTree = (tree = [], action = () => {}) => { return tree.map((item) => { const newItem = action({ ...item }) || item; if (newItem.children) { newItem.children = deepTree(newItem.children, action); } return newItem; }); };複製程式碼
右鍵選單作用在title上,需要把Dropdown寫入樹形元件的資料來源上:
<DirectoryTree style={{ width: 280 }} draggable onDrop={onDrop} defaultExpandAll onRightClick={({ node }) => setRightClickKey(node.key)} onSelect={onSelect} selectedKeys={rightConnect ? [activeTabKey] : selectedKeys} onExpand={onExpand} treeData={[ ...deepTree(treeData, (item) => { return { ...item, titleWord: item.title, title: ( <Dropdown trigger="contextMenu" visible={rightClickKey === item.key} onVisibleChange={() => setRightClickKey()} overlayStyle={{ width: 80 }} overlay={menu(item)} > <div style={ searchWord && item.title.includes(searchWord) ? { color: 'red' } : {} } > {item.title} </div> </Dropdown> ), }; }), ]} />複製程式碼
關於右鍵選單有幾點需要補充說明一下:
.ant-tree-node-content-wrapper { display: flex; }.ant-tree-title { flex: 1; }複製程式碼
const menu = (node) => ( <Menu onClick={({ key, domEvent }) => { domEvent.stopPropagation(); console.log('menuClick', node, key); // 如果要新增操作頂層資料夾,可以直接操作 switch (key) { case 'add': setTreeData( deepTree(treeData, (item) => { if (item.children && item.key === node.key) { return { ...item, children: [ ...item.children, { title: 'new add', key: shortid.generate(), isLeaf: true, }, ], }; } }) ); break; case 'delete': const outer = treeData.find((item) => item.key === node.key); if (outer) { setTreeData(treeData.filter((item) => item.key !== node.key)); return; } setTreeData( deepTree(treeData, (item) => { if (item.children) { return { ...item, children: item.children.filter( ({ key }) => key !== node.key ), }; } return item; }) ); break; case 'edit': setTreeData( deepTree(treeData, (item) => { if (item.key === node.key) { console.log('editle', { ...item, title: 'new edit', }); return { ...item, title: 'new edit', }; } return item; }) ); break; } }} > <Menu.Item key="add">新增</Menu.Item> <Menu.Item key="delete" danger> 刪除 </Menu.Item> <Menu.Item key="edit">編輯</Menu.Item> </Menu> );複製程式碼
新增功能預設只能給資料夾新增,通過key值判斷新增,這裡處理的比較簡單,只做核心功能演示,程式碼見上一小節;
修改功能也做了簡單的範例,在正式專案中一般需要彈窗編輯或者在樹元件的title中嵌入輸入框,可以使用變數記錄正在編輯的item, 最後儲存通過遞迴插入到樹形資料中:
刪除功能做了判斷,如果是刪除最外層,則直接通過filter過濾,⚠️否則刪除功能是通過children來過濾的,這裡要特別注意下。
搜尋功能是通過titile顏色變紅來提示的:
實現上也只是做了點選搜尋之後搜尋,沒有實時搜尋提示,也沒有做搜尋詞區分,這裡可以再擷取下字串來實現,可以見官方範例,注意這個預設開啟父節點的屬性autoExpandParent,否則可能要費些功夫向上遞迴。
還有一種需求是要過濾資料來源,可以對官方範例簡單改造後實現;
點選Tree元件item,在右側新增Tab,或者啟用Tab,這可以算是正向定位;那反向定位就是當右側Tab頁切換時左側Tree元件選中對應item,核心程式碼也就是指定selectedKeys,相比較而言也不難,難點在預設開啟相關父節點,當然前面說過了控制好autoExpandParent這個屬性,就好了。
拖拽移動一是Tree元件本身支援,二是官方已經給出了拖拽移動範例,我也只是在官方範例稍微做了改造,這裡也不多贅述:
搜尋和反向定位的難點其實是在,開啟關聯資料夾上,不過官方範例中使用了autoExpandParent這個屬性,一下子簡單了很多。
時候也不早了,今天就到這裡了。
更多程式設計相關知識,請存取:!!
以上就是Ant Design建立一個樹形元件,實現編輯、搜尋和定位功能的詳細內容,更多請關注TW511.COM其它相關文章!