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 を有効にすると、未読み込みのノードを展開する際に load コールバックが呼ばれます(resolve が子ノードを登録して展開、reject はキャンセル)。読み込み中は矢印が回転表示になります。 読み込み可能なノードは isLeaf: false を明示的に宣言してください(そうしないと、children を持たないノードは葉と推論され、展開矢印が表示されません)。 読み込まれた子ノードがさらに読み込み待ちのブランチである場合も同様に isLeaf: false を宣言し、本当の葉には isLeaf: true を宣言します。

遅延読み込み
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: '子ノード 1', isLeaf: true },
        { key: 'lazy-2', label: '子ノード 2', isLeaf: true },
      ])
    } else {
      reject(new Error('nothing to load'))
    }
  }, 600)
}
</script>

<template>
  <!-- 遅延読み込み -->
  <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: '子ノード 1', isLeaf: true },
            { key: 'lazy-2', label: '子ノード 2', isLeaf: true },
          ])
        } else {
          reject(new Error('nothing to load'))
        }
      }, 600)
    },
  },
}
</script>

<template>
  <!-- 遅延読み込み -->
  <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
lazy遅延読み込みモード(未読み込みノードの展開時に load を呼ぶ)booleanfalse
load遅延読み込みコールバック(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)
nodeLoad遅延読み込みの子ノードが返された後に発火(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 パターン):↑/↓ で項目間を移動(無効化をスキップ、ループ)、→ で展開または最初の子へ、← で折りたたみまたは親へ戻る、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
  /** 遅延読み込みモード:未読み込みの非葉ノードの展開時に load を呼ぶ */
  lazy?: boolean
  /** 遅延読み込みコールバック: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'

国風の美で、コードの基を築く