树
- composables
- components
- 主页
- app.vue
- nuxt.config.ts
目录结构
特性
- 可以受控或不受控。
- 焦点完全由系统管理。
- 完整的键盘导航。
- 支持从右到左的方向。
- 支持多选。
- 不同的选择行为。
安装
从命令行安装此组件。
$ npm add reka-ui结构
导入所有部分并将其组合。
<script setup>
import { TreeItem, TreeRoot, TreeVirtualizer } from 'reka-ui'
</script>
<template>
  <TreeRoot>
    <TreeItem />
    <!-- or with virtual -->
    <TreeVirtualizer>
      <TreeItem />
    </TreeVirtualizer>
  </TreeRoot>
</template>API 参考
根
包含树的所有部分。
| 属性 | 默认 | 类型 | 
|---|---|---|
| as | 'ul' | AsTag | Component此组件应渲染为的元素或组件。可通过  | 
| asChild | 布尔值更改默认渲染元素为作为子项传递的元素,合并它们的属性和行为。 阅读我们的 组合指南了解更多详情。 | |
| bubbleSelect | 布尔值当  | |
| defaultExpanded | string[]初始渲染时展开树的值。当您不需要控制展开树的状态时使用。 | |
| defaultValue | Record<string, any> | Record<string, any>[]初始渲染时树的值。当您不需要控制树的状态时使用。 | |
| dir | 'ltr' | 'rtl'列表框的阅读方向(适用时)。 | |
| disabled | 布尔值当  | |
| expanded | string[]展开项的受控值。可以与  | |
| getChildren | val.children | ((val: Record<string, any>) => Record<string, any>[])此函数传入每个项目的索引,并应返回该项目的子项列表。 | 
| getKey* | (val: Record<string, any>): string此函数传入每个项目的索引,并应返回该项目的唯一键。 | |
| items | Record<string, any>[]项目列表 | |
| modelValue | Record<string, any> | Record<string, any>[]树的受控值。可以与  | |
| multiple | 布尔值是否可以选择多个选项。 | |
| propagateSelect | 布尔值当  | |
| selectionBehavior | 'toggle' | 'toggle' | 'replace'多选在此集合中的行为方式。 | 
| 事件触发 | 载荷 | 
|---|---|
| update:expanded | [val: string[]] | 
| update:modelValue | [val: Record<string, any> | Record<string, any>[]]当切换组件的值改变时调用的事件处理程序。 | 
| 插槽(默认) | 载荷 | 
|---|---|
| flattenItems | FlattenedItem<Record<string, any>>[] | 
| modelValue | Record<string, any> | Record<string, any>[] | 
| expanded | string[] | 
项
项目组件。
| 属性 | 默认 | 类型 | 
|---|---|---|
| as | 'li' | AsTag | Component此组件应渲染为的元素或组件。可通过  | 
| asChild | 布尔值更改默认渲染元素为作为子项传递的元素,合并它们的属性和行为。 阅读我们的 组合指南了解更多详情。 | |
| level* | 数字深度级别 | |
| 值* | Record<string, any>赋予此项的值 | 
| 事件触发 | 载荷 | 
|---|---|
| select | [event: SelectEvent<Record<string, any>>]选择项时调用的事件处理程序。 | 
| toggle | [event: ToggleEvent<Record<string, any>>]选择项时调用的事件处理程序。 | 
| 插槽(默认) | 载荷 | 
|---|---|
| isExpanded | 布尔值 | 
| isSelected | 布尔值 | 
| isIndeterminate | boolean | undefined | 
| handleToggle | (): void | 
| handleSelect | (): void | 
| 数据属性 | 值 | 
|---|---|
| [data-indent] | Number | 
| [data-expanded] | 展开时存在 | 
| [data-selected] | 选中时存在 | 
虚拟化器
用于实现列表虚拟化的虚拟容器。
| 属性 | 默认 | 类型 | 
|---|---|---|
| estimateSize | 数字每个项的估计大小(以像素为单位) | |
| overscan | 数字在可见区域之外渲染的项目数量 | |
| textContent | ((item: Record<string, any>) => string)每个项的文本内容,以实现预输入功能 | 
| 插槽(默认) | 载荷 | 
|---|---|
| item | FlattenedItem<Record<string, any>> | 
| virtualizer | Virtualizer<Element | Window, Element> | 
| virtualItem | VirtualItem | 
示例
选择多个项目
Tree 组件允许您选择多个项目。您可以通过提供一个值数组而不是单个值,并将 multiple="true" 来启用此功能。
<script setup lang="ts">
import { TreeRoot } from 'reka-ui'
import { ref } from 'vue'
const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]
const selectedPeople = ref([people[0], people[1]])
</script>
<template>
  <TreeRoot
    v-model="selectedPeople"
    multiple
  >
    ...
  </TreeRoot>
</template>虚拟列表
渲染长列表项目可能会拖慢应用程序,因此使用虚拟化将显著提高性能。
有关虚拟化的更多通用信息,请参阅虚拟化指南。
<script setup lang="ts">
import { TreeItem, TreeRoot, TreeVirtualizer } from 'reka-ui'
import { ref } from 'vue'
</script>
<template>
  <TreeRoot :items>
    <TreeVirtualizer
      v-slot="{ item }"
      :text-content="(opt) => opt.name"
    >
      <TreeItem v-bind="item.bind">
        {{ person.name }}
      </TreeItem>
    </TreeVirtualizer>
  </TreeRoot>
</template>带复选框
某些 Tree 组件可能希望显示 选中/不确定 状态的复选框。我们可以通过使用一些属性和 preventDefault 事件来改变 Tree 组件的行为。
我们将 propagateSelect 设置为 true,因为我们希望父复选框能够选择/取消选择其后代。然后,我们添加一个触发 select 事件的复选框。
<script setup lang="ts">
import { TreeItem, TreeRoot } from 'reka-ui'
import { ref } from 'vue'
</script>
<template>
  <TreeRoot
    v-slot="{ flattenItems }"
    :items
    multiple
    propagate-select
  >
    <TreeItem
      v-for="item in flattenItems"
      :key="item._id"
      v-bind="item.bind"
      v-slot="{ handleSelect, isSelected, isIndeterminate }"
      @select="(event) => {
        if (event.detail.originalEvent.type === 'click')
          event.preventDefault()
      }"
      @toggle="(event) => {
        if (event.detail.originalEvent.type === 'keydown')
          event.preventDefault()
      }"
    >
      <Icon
        v-if="item.hasChildren"
        icon="radix-icons:chevron-down"
      />
      <button
        tabindex="-1"
        @click.stop
        @change="handleSelect"
      >
        <Icon
          v-if="isSelected"
          icon="radix-icons:check"
        />
        <Icon
          v-else-if="isIndeterminate"
          icon="radix-icons:dash"
        />
        <Icon
          v-else
          icon="radix-icons:box"
        />
      </button>
      <div class="pl-2">
        {{ item.value.title }}
      </div>
    </TreeItem>
  </TreeRoot>
</template>嵌套树节点
默认示例显示扁平化的树项目和节点,这使得 虚拟化 和拖放等自定义功能更容易实现。但是,您也可以构建它以拥有嵌套的 DOM 节点。
在 Tree.vue 中,
<script setup lang="ts">
import { TreeItem } from 'reka-ui'
interface TreeNode {
  title: string
  icon: string
  children?: TreeNode[]
}
withDefaults(defineProps<{
  treeItems: TreeNode[]
  level?: number
}>(), { level: 0 })
</script>
<template>
  <li
    v-for=" tree in treeItems"
    :key="tree.title"
  >
    <TreeItem
      v-slot="{ isExpanded }"
      as-child
      :level="level"
      :value="tree"
    >
      <button>…</button>
      <ul v-if="isExpanded && tree.children">
        <Tree
          :tree-items="tree.children"
          :level="level + 1"
        />
      </ul>
    </TreeItem>
  </li>
</template>在 CustomTree.vue 中
<template>
  <TreeRoot
    :items="items"
    :get-key="(item) => item.title"
  >
    <Tree :tree-items="items" />
  </TreeRoot>
</template>自定义子项模式
默认情况下,<TreeRoot /> 要求您通过为每个节点传递 children 列表来提供节点的子项列表。您可以通过提供 getChildren 属性来覆盖此行为。
如果节点没有子项,getChildren 应该返回 undefined 而不是空数组。
<script setup lang="ts">
import { TreeRoot } from 'reka-ui'
import { ref } from 'vue'
interface FileNode {
  title: string
  icon: string
}
interface DirectoryNode {
  title: string
  icon: string
  directories?: DirectoryNode[]
  files?: FileNode[]
}
</script>
<template>
  <TreeRoot
    :items="items"
    :get-key="(item) => item.title"
    :get-children="(item) => (!item.files) ? item.directories : (!item.directories) ? item.files : [...item.directories, ...item.files]"
  >
    ...
  </TreeRoot>
</template>可拖动/可排序树
对于更复杂的拖动 Tree 组件,在此示例中我们将使用 pragmatic-drag-and-drop 作为处理拖放的核心包。
可访问性
遵循 树 WAI-ARIA 设计模式。
键盘交互
| 键 | 描述 | 
|---|---|
| 回车键 | 当焦点在  TreeItem上时,选择该焦点项目。 | 
| 向下箭头键 | 当焦点在  TreeItem上时,将焦点移到下一个项目。 | 
| 向上箭头键 | 当焦点在  TreeItem上时,将焦点移到上一个项目。 | 
| 向右箭头 | 当焦点在关闭的  TreeItem(节点)上时,它会打开节点而不移动焦点。当在打开的节点上时,它将焦点移到第一个子节点。当在末尾节点上时,它不做任何操作。 | 
| 向左箭头 | 当焦点在打开的  TreeItem(节点)上时,关闭节点。当焦点在既是末尾节点又是关闭节点的子节点上时,将焦点移到其父节点。当焦点在既是末尾节点又是关闭节点的根节点上时,不做任何操作。 | 
| HomePageUp | 将焦点移到第一个  TreeItem | 
| EndPageDown | 将焦点移到最后一个  TreeItem | 
