Skip to content
API 风格:

Tree 樹狀元件 ​

扁平資料 → 樹的轉換與勾選傳播都在 core 純函式裡完成,元件只負責渲染與鍵盤。

基礎用法 ​

基礎用法
前端
Vue
React
運維
vue
<script setup>
import { ref } from 'vue'
const treeData = [
  { key: 'a', label: '前端', children: [
    { key: 'a-1', label: 'Vue' },
    { key: 'a-2', label: 'React' },
  ] },
  { key: 'b', label: '后端', children: [{ key: 'b-1', label: 'Node' }] },
  { key: 'c', label: '运维', disabled: true },
]
</script>

<template>
  <!-- 基礎用法 -->
  <LhTree :data="treeData" :default-expanded-keys="['a']" />
</template>
vue
<script>
export default {
  data() {
    return {
      treeData: [
        { key: 'a', label: '前端', children: [
          { key: 'a-1', label: 'Vue' },
          { key: 'a-2', label: 'React' },
        ] },
        { key: 'b', label: '后端', children: [{ key: 'b-1', label: 'Node' }] },
        { key: 'c', label: '运维', disabled: true },
      ],
    }
  },
}
</script>

<template>
  <!-- 基礎用法 -->
  <LhTree :data="treeData" :default-expanded-keys="['a']" />
</template>

可勾選(級聯) ​

勾選父級會級聯全部後代;子級全選時父級自動選中,部分選中顯示半選態(indeterminate)。

勾選級聯
前端
Vue
React
後端
Node
運維
vue
<script setup lang="ts">
const treeData = [
  { key: 'a', label: '前端', children: [
    { key: 'a-1', label: 'Vue' },
    { key: 'a-2', label: 'React' },
  ] },
  { key: 'b', label: '后端', children: [{ key: 'b-1', label: 'Node' }] },
  { key: 'c', label: '运维', disabled: true },
]
</script>

<template>
  <!-- 勾選級聯 -->
  <LhTree :data="treeData" show-checkbox :default-expanded-keys="['a', 'b']" />
</template>
vue
<script>
export default {
  data() {
    return {
      treeData: [
        { key: 'a', label: '前端', children: [
          { key: 'a-1', label: 'Vue' },
          { key: 'a-2', label: 'React' },
        ] },
        { key: 'b', label: '后端', children: [{ key: 'b-1', label: 'Node' }] },
        { key: 'c', label: '运维', disabled: true },
      ],
    }
  },
}
</script>

<template>
  <!-- 勾選級聯 -->
  <LhTree :data="treeData" show-checkbox :default-expanded-keys="['a', 'b']" />
</template>

Lazy 載入 ​

開啟 lazy 後,展開未載入的節點會呼叫 load 回呼(resolve 提交子節點並展開,reject 取消);載入中箭頭顯示旋轉態。 可載入節點須明確宣告 isLeaf: false(否則無 children 的節點會被推斷為葉子、不顯示展開箭頭); 載入下來的子節點如仍是待載入分支,同樣宣告 isLeaf: false,真葉子宣告 isLeaf: true。

Lazy 載入
vue
<script setup>
import { ref } from 'vue'

const lazyData = ref([
  { key: 'lazy', label: '点我加载', isLeaf: false },
])

function loadNodes(node, resolve, reject) {
  // 模擬非同步請求
  setTimeout(() => {
    if (node.key === 'lazy') {
      resolve([
        { key: 'lazy-1', label: '子节点一', isLeaf: true },
        { key: 'lazy-2', label: '子节点二', isLeaf: true },
      ])
    } else {
      reject(new Error('nothing to load'))
    }
  }, 600)
}
</script>

<template>
  <!-- Lazy 載入 -->
  <LhTree :data="lazyData" lazy :load="loadNodes" />
</template>
vue
<script>
export default {
  data() {
    return {
      lazyData: [{ key: 'lazy', label: '点我加载', isLeaf: false }],
    }
  },
  methods: {
    // 模擬非同步請求
    loadNodes(node, resolve, reject) {
      setTimeout(() => {
        if (node.key === 'lazy') {
          resolve([
            { key: 'lazy-1', label: '子节点一', isLeaf: true },
            { key: 'lazy-2', label: '子节点二', isLeaf: true },
          ])
        } else {
          reject(new Error('nothing to load'))
        }
      }, 600)
    },
  },
}
</script>

<template>
  <!-- Lazy 載入 -->
  <LhTree :data="lazyData" lazy :load="loadNodes" />
</template>

父子不聯動(checkStrictly) ​

開啟 checkStrictly 後勾選只作用於節點自身:不級聯後代、不回溯祖先、無半選態。

checkStrictly
前端
Vue
React
後端
Node
運維
vue
<script setup lang="ts">
const treeData = [
  { key: 'a', label: '前端', children: [
    { key: 'a-1', label: 'Vue' },
    { key: 'a-2', label: 'React' },
  ] },
  { key: 'b', label: '后端', children: [{ key: 'b-1', label: 'Node' }] },
  { key: 'c', label: '运维', disabled: true },
]
</script>

<template>
  <!-- 父子不聯動 -->
  <LhTree :data="treeData" show-checkbox check-strictly :default-expanded-keys="['a', 'b']" />
</template>
vue
<script>
export default {
  data() {
    return {
      treeData: [
        { key: 'a', label: '前端', children: [
          { key: 'a-1', label: 'Vue' },
          { key: 'a-2', label: 'React' },
        ] },
        { key: 'b', label: '后端', children: [{ key: 'b-1', label: 'Node' }] },
        { key: 'c', label: '运维', disabled: true },
      ],
    }
  },
}
</script>

<template>
  <!-- 父子不聯動 -->
  <LhTree :data="treeData" show-checkbox check-strictly :default-expanded-keys="['a', 'b']" />
</template>

選中與受控鍵值 ​

multiple 允許多選;expand-on-click-node 點擊節點即展開/收起;default-selected-keys / v-model:selected-keys 受控選中;default-checked-keys / v-model:checked-keys 受控勾選;default-expanded-keys / v-model:expanded-keys 受控展開;disabled 停用整棵樹。

受控選中與勾選
設計
色彩
字體
工程

選中:[ "x" ] | 勾選:[ "x-1" ]

停用整棵樹
工程
vue
<script setup>
import { ref } from 'vue'
const selKeys = ref(['x'])
const chkKeys = ref(['x-1'])
const ctrlData = [
  { key: 'x', label: '设计', children: [
    { key: 'x-1', label: '色彩' },
    { key: 'x-2', label: '字体' },
  ] },
  { key: 'y', label: '工程' },
]
</script>

<template>
  <!-- 受控選中與勾選 -->
  <LhTree
    v-model:selected-keys="selKeys"
    v-model:checked-keys="chkKeys"
    :data="ctrlData"
    multiple
    expand-on-click-node
    :default-expanded-keys="['x']"
    :default-selected-keys="['x']"
    :default-checked-keys="['x-1']"
  />
  <p class="demo-tree-log">选中:{{ selKeys }} | 勾选:{{ chkKeys }}</p>
  <!-- 停用整棵樹 -->
  <LhTree :data="ctrlData" disabled />
</template>
vue
<script>
export default {
  data() {
    return {
      selKeys: ['x'],
      chkKeys: ['x-1'],
      ctrlData: [
        { key: 'x', label: '设计', children: [
          { key: 'x-1', label: '色彩' },
          { key: 'x-2', label: '字体' },
        ] },
        { key: 'y', label: '工程' },
      ],
    }
  },
}
</script>

<template>
  <!-- 受控選中與勾選 -->
  <LhTree
    v-model:selected-keys="selKeys"
    v-model:checked-keys="chkKeys"
    :data="ctrlData"
    multiple
    expand-on-click-node
    :default-expanded-keys="['x']"
    :default-selected-keys="['x']"
    :default-checked-keys="['x-1']"
  />
  <p class="demo-tree-log">选中:{{ selKeys }} | 勾选:{{ chkKeys }}</p>
  <!-- 停用整棵樹 -->
  <LhTree :data="ctrlData" disabled />
</template>

API ​

LhTree Props ​

屬性名說明類型預設值
data樹狀資料[LhTreeNode](#type-LhTreeNode)[]—
showCheckbox顯示勾選框booleanfalse
multiple多選(點擊節點切換選中而非替換)booleanfalse
expandOnClickNode點擊非葉子節點時展開/收起booleantrue
defaultExpandedKeys預設展開的鍵(非受控)string[]() => []
expandedKeys受控展開的鍵string[]—
defaultSelectedKeys預設選中的鍵(非受控)string[]() => []
selectedKeys受控選中的鍵string[]—
defaultCheckedKeys預設勾選的鍵(非受控)string[]() => []
checkedKeys受控勾選的鍵string[]—
checkStrictly父子勾選不聯動(勾選只作用於自身,無級聯與半選)booleanfalse
lazyLazy 載入模式(展開未載入節點時呼叫 load)booleanfalse
loadLazy 載入回呼(resolve 提交子節點並展開,reject 取消)(node: LhTreeNode, resolve: (children: LhTreeNode[]) => void, reject: (reason?: unknown) => void) => void—
disabled整體停用booleanfalse
sxsx 快速版面配置屬性LhSxProps—

Events ​

事件名說明回呼參數
update:expandedKeys展開鍵列表變化時觸發,配合 v-model:expanded-keys 使用(keys: string[])
update:selectedKeys選中鍵列表變化時觸發,配合 v-model:selected-keys 使用(keys: string[])
update:checkedKeys勾選鍵列表變化時觸發,配合 v-model:checked-keys 使用(keys: string[])
select節點被點擊選中 / 切換選中後觸發(key: string, node: LhTreeNode)
check勾選變化後觸發(keys: string[], node: LhTreeNode)
expand節點展開 / 收起後觸發(key: string, expanded: boolean)
nodeLoadLazy 載入子節點傳回後觸發(node: LhTreeNode, children: LhTreeNode[])

插槽:node(作用域 { node, level, expanded, selected })、empty。

LhTreeNode ​

欄位說明類型
key唯一鍵string
label顯示文字string
children子節點LhTreeNode[]
disabled停用boolean
isLeaf是否葉子(不傳按 children 推斷)boolean

無障礙 ​

  • role="tree" + role="treeitem",aria-level / aria-expanded / aria-selected / aria-disabled 全量暴露
  • 勾選框 role="checkbox" + aria-checked(半選為 mixed)
  • 鍵盤(APG tree pattern):↑/↓ 項間移動(跳過停用、循環)、→ 展開或進首子、← 收起或回父級、Home/End 首末、Enter/Space 啟用;roving tabindex

類型定義 ​

本元件對外匯出的 TypeScript 類型結構如下(自動提取自 packages/components/tree/src/types.ts 與 @lh-ui/share/core/* 原始碼,點選各條目展開檢視完整定義;屬性說明見上方 Props 表):

LhTreeProps
ts
export interface LhTreeProps {
  /** 樹狀資料 */
  data: LhTreeNode[]
  /** 顯示勾選框 */
  showCheckbox?: boolean
  /** 多選(點擊節點切換選中而非替換) */
  multiple?: boolean
  /** 點擊非葉子節點時展開/收起 */
  expandOnClickNode?: boolean
  /** 預設展開的鍵(非受控) */
  defaultExpandedKeys?: string[]
  /** 受控展開的鍵 */
  expandedKeys?: string[]
  /** 預設選中的鍵(非受控) */
  defaultSelectedKeys?: string[]
  /** 受控選中的鍵 */
  selectedKeys?: string[]
  /** 預設勾選的鍵(非受控) */
  defaultCheckedKeys?: string[]
  /** 受控勾選的鍵 */
  checkedKeys?: string[]
  /** 父子勾選不聯動(勾選只作用於節點自身,無級聯與半選) */
  checkStrictly?: boolean
  /** Lazy 載入模式:展開未載入的非葉子節點時呼叫 load */
  lazy?: boolean
  /** Lazy 載入回呼:resolve 提交子節點並展開,reject(或拋錯)取消 */
  load?: (
    node: LhTreeNode,
    resolve: (children: LhTreeNode[]) => void,
    reject: (reason?: unknown) => void,
  ) => void
  /** 整體停用 */
  disabled?: boolean
  /** sx 快速版面配置屬性 */
  sx?: LhSxProps
}
LhFlatTreeNode (來自 @lh-ui/share/core/tree)
ts
/** 扁平化後的節點(渲染用) */
export interface LhFlatTreeNode {
  node: LhTreeNode
  key: string
  level: number
  parentKey: string | null
  /** 祖先鏈(不含自身) */
  ancestorKeys: string[]
  /** 是否葉子 */
  isLeaf: boolean
}
LhTreeNode (來自 @lh-ui/share/core/tree)
ts
/** 樹狀節點資料 */
export interface LhTreeNode {
  /** 唯一鍵 */
  key: string
  /** 顯示文字 */
  label: string
  /** 子節點 */
  children?: LhTreeNode[]
  /** 停用 */
  disabled?: boolean
  /** 是否葉子(不傳按 children 推斷) */
  isLeaf?: boolean
}
LhTreeCheckState (來自 @lh-ui/share/core/tree)
ts
/** 勾選狀態 */
export type LhTreeCheckState = 'checked' | 'indeterminate' | 'unchecked'