【我要做開源】Vue DevUI開源指南02:實現一個能渲染多層節點的Tree元件

語言: CN / TW / HK

歡迎大家圍觀Kagol和村長的直播,手把手帶你一起為Vue DevUI開源元件庫提交PR。

也歡迎大家參與到Vue DevUI的建設中來,可以加小助手微信 devui-official

Vue DevUI程式碼倉庫:

https://gitee.com/devui/vue-devui

B站直播連結:

https://www.bilibili.com/video/BV1GU4y1N7eC

以下是正文:

渲染一層樹節點

上一期直播我們給大家分享瞭如何給Vue DevUI開源元件庫提交第一個PR,並以tree元件為例子,介紹如何給Vue DevUI貢獻元件,上次只開了個頭,寫了一個渲染一層樹節點的非常簡單的tree元件,並且只有data這一個api。

<d-tree :data="[{ label: '中國菜' }]"></d-tree>

``` import { defineComponent, toRefs } from 'vue' import { treeProps, TreeProps } from './tree-types' import './tree.scss'

export default defineComponent({ name: 'DTree', props: treeProps, emits: [], setup(props: TreeProps,) { return () => (

{ props.data.map(item =>
{item.label}
) }
) } }) ```

整體設計思路

實現一個tree元件,我們的第一直覺就是一層一層巢狀渲染子節點的dom結構,這麼做會有一個問題,就是如果一棵樹有非常多節點,並且巢狀層級非常深,我們很難用虛擬滾動的方式去進行優化,因此不可避免地導致效能問題。

我測試了ElementPlus元件庫,使用Tree元件渲染5萬個樹節點,耗時6s左右,同樣的資料量,AntDesign元件庫的Tree元件耗時10s左右,但是AntDesign的Tree元件提供了虛擬滾動功能,開啟虛擬滾動,載入時間瞬間降到1s以內,而且不會因為節點數的增加而影響效能。

而要使用虛擬滾動,就需要將巢狀結構變成平鋪結構。

為了方便使用者使用,我們設計的data屬性依然使用巢狀結構,但是元件內部需要將其拍平,並用平鋪的方式將樹節點渲染到dom中。

data結構:

data: [ { label: 'node-1', children: [ { label: 'node-11', children: [ { label: 'node-111' }, { label: 'node-112' }, ], }, { label: 'node-12', children: [ { label: 'node-121' }, { label: 'node-122' }, { label: 'node-123' }, ], }, ], }, { label: 'node-2' }, ]

DOM結構:

```

->

```

引入SVG

由於tree元件節點前面一般會有一個小圖示,為了方便使用svg圖示,我們可以藉助vite-svg-plugin外掛。

安裝vite-svg-loader外掛

yarn add -D vite-svg-loader

docs/vite.config.ts

``` import path from 'path' import { defineConfig } from 'vite' import vueJsx from '@vitejs/plugin-vue-jsx' import svgLoader from 'vite-svg-loader' // 引入vite-svg-loader外掛

export default defineConfig({ resolve: { alias: [ { find: '@devui', replacement: path.resolve(__dirname, '../devui') }, ] }, plugins: [ vueJsx({}), svgLoader(), // 使用vite-svg-loader外掛 ], }) ```

匯入svg

import IconOpen from './assets/open.svg'

open.svg

``` <svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="svg-icon svg-icon-close"

```

使用svg

```

or

setup() { return () => } ```

給節點增加一個層級的標識level

不同層級節點的縮排是不一樣的,我們需要一個level屬性來標識當前節點的層級。

第一層的level是1,第二層是2,以此類推。

data: [ { label: 'node-1', level: 1, children: [ { label: 'node-11', level: 2, children: [ { label: 'node-111', level: 3, }, { label: 'node-112', level: 3, }, ], }, { label: 'node-12', level: 2, children: [ { label: 'node-121', level: 3, }, { label: 'node-122', level: 3, }, { label: 'node-123', level: 3, }, ], }, ], }, { label: 'node-2', level: 1, }, ]

渲染多層樹節點(重點)

渲染一層節點非常簡單:

```

{ props.data.map(item =>
{item.label}
) }

```

渲染多層則需要定義一個渲染函式,在函式中做一次遞迴操作。

``` // 增加縮排的展位元素 const Indent = () => { return }

const renderNode = (item) => { return (

${24 * (item.level - 1)}px }}> { item.children ? : } { item.label }
) }

const renderTree = (tree) => { return tree.map(item => { if (!item.children) { return renderNode(item) } else { return ( <> {renderNode(item)} {renderTree(item.children)}
) } }) } ```

```

{ renderTree(props.data) }

```

實現的效果

demo文件

````

Tree 樹

一種表現巢狀結構的元件。

何時使用

資料夾、組織架構、生物分類、國家地區等等,世間萬物的大多數結構都是樹形結構。使用樹控制元件可以完整展現其中的層級關係,並具有展開收起選擇等互動功能。

基礎用法

```vue

```

Props

| 引數 | 型別 | 預設 | 說明 | 跳轉 Demo | | ------------ | ------- | ----- | ---------------------------------------- | --------- | | data | TreeData | [] | 必選,資料來源 | |

TreeData 資料結構

| 引數 | 型別 | 預設值 | 說明 | | ----------- | --------- | ------- | ------------------------------------------------------------------------ | | label | string | - | 文字內容 | | children | TreeData | - | 子節點 | ````