返回目录
组件详情入口
导航
@vean/ui
STree

Tree

Tree 属于 导航 分类。建议先看演示与用法,再对照 API 表格完成接入和样式调整。

先用快捷跳转面板找到概述、用法、演示和 API,再往下细读完整文档内容。

快速跳转

同分类组件

如果你在同一类交互里做组合,这些组件通常会一起出现。

树

概述

用于展示树形层级数据、并支持选择与展开/折叠的组件。STree 将 Aria 层 TreeRoot 一族基础原语(TreeRoot/TreeItem/TreeVirtualizerRoot/TreeVirtualizerItem,零样式)与 TreeRoot 上下文(受控/非受控选中与展开、单选/多选、级联选择、Roving Focus 键盘导航)组合;STreeVirtualizer 在其上叠加虚拟滚动,可平滑承载 1000+ 节点。节点内容完全由 item 插槽自定义,节点图标、勾选框、缩进与连接线样式均由使用方注入。

用法

特性

  • 🌳 层级数据模型 — items: TreeItemData<T>[](value + 可选 children 递归结构),TreeItemData<T> 泛型保留自定义字段类型
  • 🎛️ 受控/非受控双通道 — modelValue / defaultValue 控制选中,expanded / defaultExpanded 控制展开;均支持 v-model 与 update:* 事件回写
  • ☑️ 单选与多选 — multiple(与 modelValue 类型联动:单值字符串 ↔ 数组)切换;selectionBehavior: 'toggle' | 'replace' 决定多选点击行为;Shift + 方向键 连续范围选择
  • 🧩 级联选择 — propagateSelect(选择父节点时级联选中子孙)、bubbleSelect(子节点全部选中后自动选中父节点)、allowParentSelect(是否允许直接选中含子节点的父项)
  • 📂 展开策略 — toggleBehavior: 'multiple' | 'single'(默认多节点展开;single 下展开新节点自动折叠旧节点,行为类似手风琴)
  • ⌨️ 键盘导航 — Roving Focus:↑/↓ 移动焦点、→/← 展开/折叠或进入/返回父层级、Enter/Space 选中、字符输入 typeahead 快速定位;loop(默认 true)首尾循环;完整支持 RTL
  • ⚡ 虚拟滚动 — STreeVirtualizer + height 仅渲染可视节点,1000+ 节点仍保持流畅
  • ♿ 无障碍 — role="tree"/treeitem + aria-expanded/aria-selected/aria-level/aria-setsize/aria-posinset/aria-multiselectable/aria-disabled,配合 data-vean-tree-* 数据属性

组件家族

  • STree(styled)— 入口包装;TreeRootProps<T, U, M> 泛型透传 + useForwardListeners 事件合并 + top/item/bottom 插槽;withDefaults 镜像 Aria loop: true 默认
  • STreeVirtualizer(styled)— 虚拟滚动包装;contentProps/dynamicContentProps 转发给 VirtualizerContent,item 插槽额外暴露 virtualItem
  • TreeRoot(Aria)— 根组件;useControllableState 管理选中/展开,useSelectionBehavior 处理单选/多选/范围选择,useRovingFocusGroup + useTypeahead 实现键盘导航;provideTreeRootContext 桥接子项
  • TreeItem(Aria)— 单节点;useRovingFocusGroupItem 管理焦点,渲染 aria-* 与 data-* 属性,select/toggle 事件经 handleAndDispatchCustomEvent 派发
  • TreeVirtualizerRoot(Aria)— 虚拟化根;VirtualizerRoot + TanStack Virtual,转发扁平化 flattenItems
  • TreeVirtualizerItem(Aria)— 虚拟化节点;TreeItem + VirtualizerItem 组合(data-vean-tree-virtualizer-item)

演示

基础

    Directory Structure

  • components
  • app.vue
  • nuxt.config.ts

虚拟列表

  • 01 Basic — 基础目录树(items + default-expanded + top 插槽)
  • 02 Virtualizer — STreeVirtualizer 虚拟滚动渲染 1000+ 节点

API

Aria 层

6

Tree<T>

3 插槽
插槽
插槽名参数描述
top
—
树节点渲染前的内容。
bottom
—
树节点之后渲染的内容。
item
{ item: FlattenedItem<T>; modelValue: MaybeArray<string> | undefined; expanded: string[]; }
单个树节点的内容。

TreeItem

7 属性2 事件
属性
属性名类型默认值描述
value
string
—
与当前项关联的值。
level
number
—
难度等级。
disabled
boolean
—
当值为 `true` 时,禁止用户选择或切换该项。
disabledSelect
boolean
—
当值为 `true` 时,禁止用户选择该项。
disabledToggle
boolean
—
当值为 `true` 时,禁止用户切换该项。
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。
事件
事件名参数描述
select
TreeSelectEvent<string>
选择项目时调用的事件处理程序。
toggle
TreeToggleEvent<string>
切换项目时调用的事件处理程序。

TreeRoot<T, U, M>

16 属性2 事件
属性
属性名类型默认值描述
modelValue
U
—
树的受控值。可通过 `v-model` 进行绑定。
defaultValue
U
—
树在初始渲染时的值。当不需要控制树的状态时使用
multiple
IsMultiple<U, M>
—
用于确定一次可选择“单个”还是“多个”项目。
items
T[]
—
项目列表
expanded
string[]
—
展开项的受控值。可通过 `v-model` 进行绑定。
defaultExpanded
string[]
—
初始渲染时展开树的值。
selectionBehavior
TreeSelectBehavior
—
集合中多选功能应如何工作。
toggleBehavior
TreeToggleBehavior
'multiple'
用于确定一次可切换的项是“单个”还是“多个”。
dir
Direction
—
阅读方向。
loop
boolean
true
当值为 `true` 时,键盘导航将在最后一项和第一项之间循环切换。
disabled
boolean
—
当设置为 `true` 时,禁止用户与树结构进行交互
propagateSelect
boolean
—
当值为 `true` 时,选中父节点将同时选中其子节点。
bubbleSelect
boolean
—
当值为 `true` 时,选择子节点将更新父节点的状态。
allowParentSelect
boolean
—
当值为 `true` 时,可选中父元素。
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。
事件
事件名参数描述
update:modelValue
M extends true ? string[] : string
当模型值发生变化时触发。
update:expanded
string[]
在展开状态发生变化时触发。

TreeVirtualizer<T, U, M>

22 属性2 事件
属性
属性名类型默认值描述
contentProps
VirtualizerContentProps
—
转发给内容元素的属性。
dynamicContentProps
VirtualizerDynamicContentProps
—
转发给动态内容元素的属性。
animated
boolean
false
当设置为 `true` 时,将可见项目渲染在正常文档流中(动态模式),因此 在展开/折叠操作中,项目位置将保持正确,无需绝对偏移量。
modelValue
U
—
树的受控值。可通过 `v-model` 进行绑定。
defaultValue
U
—
树在初始渲染时的值。当不需要控制树的状态时使用
multiple
IsMultiple<U, M>
—
用于确定一次可选择“单个”还是“多个”项目。
items
T[]
—
项目列表
expanded
string[]
—
展开项的受控值。可通过 `v-model` 进行绑定。
defaultExpanded
string[]
—
初始渲染时展开树的值。
selectionBehavior
TreeSelectBehavior
—
集合中多选功能应如何工作。
toggleBehavior
TreeToggleBehavior
'multiple'
用于确定一次可切换的项是“单个”还是“多个”。
dir
Direction
—
阅读方向。
loop
boolean
true
当值为 `true` 时,键盘导航将在最后一项和第一项之间循环切换。
disabled
boolean
—
当设置为 `true` 时,禁止用户与树结构进行交互
propagateSelect
boolean
—
当值为 `true` 时,选中父节点将同时选中其子节点。
bubbleSelect
boolean
—
当值为 `true` 时,选择子节点将更新父节点的状态。
allowParentSelect
boolean
—
当值为 `true` 时,可选中父元素。
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。
height
string | number
—
虚拟化器根目录的高度
options
VirtualizerOptions
—
选项。
dynamic
boolean
—
是否为动态内容。
事件
事件名参数描述
update:modelValue
M extends true ? string[] : string
当模型值发生变化时触发。
update:expanded
string[]
在展开状态发生变化时触发。

TreeVirtualizerItem

9 属性2 事件
属性
属性名类型默认值描述
value
string
—
与当前项关联的值。
level
number
—
难度等级。
disabled
boolean
—
当值为 `true` 时,禁止用户选择或切换该项。
disabledSelect
boolean
—
当值为 `true` 时,禁止用户选择该项。
disabledToggle
boolean
—
当值为 `true` 时,禁止用户切换该项。
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。
data
VirtualItem
—
数据。
customStyle
boolean
—
是否采用自定义样式。
事件
事件名参数描述
select
TreeSelectEvent<string>
选择项目时调用的事件处理程序。
toggle
TreeToggleEvent<string>
切换项目时调用的事件处理程序。

TreeVirtualizerRoot<T, U, M>

19 属性2 事件
属性
属性名类型默认值描述
modelValue
U
—
树的受控值。可通过 `v-model` 进行绑定。
defaultValue
U
—
树在初始渲染时的值。当不需要控制树的状态时使用
multiple
IsMultiple<U, M>
—
用于确定一次可选择“单个”还是“多个”项目。
items
T[]
—
项目列表
expanded
string[]
—
展开项的受控值。可通过 `v-model` 进行绑定。
defaultExpanded
string[]
—
初始渲染时展开树的值。
selectionBehavior
TreeSelectBehavior
—
集合中多选功能应如何工作。
toggleBehavior
TreeToggleBehavior
'multiple'
用于确定一次可切换的项是“单个”还是“多个”。
dir
Direction
—
阅读方向。
loop
boolean
true
当值为 `true` 时,键盘导航将在最后一项和第一项之间循环切换。
disabled
boolean
—
当设置为 `true` 时,禁止用户与树结构进行交互
propagateSelect
boolean
—
当值为 `true` 时,选中父节点将同时选中其子节点。
bubbleSelect
boolean
—
当值为 `true` 时,选择子节点将更新父节点的状态。
allowParentSelect
boolean
—
当值为 `true` 时,可选中父元素。
asChild
boolean
—
将默认渲染元素替换为作为子元素传递的元素,并合并两者的属性及行为。
as
AsTag | Component
'div'
该组件应渲染为的元素或组件。可通过 `asChild` 进行覆盖。
height
string | number
—
虚拟化器根目录的高度
options
VirtualizerOptions
—
选项。
dynamic
boolean
—
是否为动态内容。
事件
事件名参数描述
update:modelValue
M extends true ? string[] : string
当模型值发生变化时触发。
update:expanded
string[]
在展开状态发生变化时触发。

说明

架构与对标差异

TreeRoot 拥有全部状态(选中/展开经 useControllableState 受控/非受控双通道)与选择策略(useSelectionBehavior 的 toggle/replace/范围选择),所有基础原语保持零样式;STree/STreeVirtualizer 仅负责 loop 默认值镜像与插槽透传,节点视觉完全由 item 插槽内的 STreeItem/STreeVirtualizerItem 组合实现(缩进、图标、勾选框、焦点态均经类名注入)。键盘导航基于 Roving Focus(↑/↓ 移动、→/← 展开/折叠、typeahead 定位),并额外支持 Shift 范围选择——该交互超出多数主流库的树组件默认契约。虚拟滚动基于 @vean/aria 内置 virtualizer,仅渲染可视节点。

能力VeanUIAnt DesignElement PlusNaive UI
Aria/样式分离✅———
单选/多选(multiple + toggle/replace)✅✅✅✅
展开策略(single/multiple toggle)✅✅✅✅
级联选择(propagate/bubble/parent)✅✅✅⚠️
键盘导航(方向键 + 循环 + typeahead)✅✅✅⚠️
虚拟滚动(1k 节点)✅✅⚠️✅
可勾选模式(checkable 复选框)⚠️✅✅✅
拖拽排序(draggable)—✅✅✅
异步加载子节点(loadData)—✅✅✅
搜索过滤(searchValue)—✅✅—

⚠️ = 部分支持(VeanUI 的 checkable 可经 multiple + 自定义 item 插槽勾选图标 + data-selected/data-contains-selected 状态实现;Naive UI 无内置范围选择与字符定位)。

注意事项

  • modelValue 类型与 multiple 联动:modelValue 为单值字符串时强制单选;为数组且 multiple 为真时启用多选(IsMultiple<U, M> 条件类型约束)。
  • item 插槽是自由组合模式:必须由使用方渲染 STreeItem(或 STreeVirtualizerItem)并传入 item.value/item.level;插槽同时暴露 item.data(原始节点数据)、isExpanded/isSelected/isIndeterminate/hasChildren 等状态。
  • 含子节点的父项默认不可选中(allowParentSelect 默认 false);需要父项可选中时显式开启。
  • propagateSelect/bubbleSelect 仅在多选(multiple + 数组值)下生效;两者同时开启时以 data-contains-selected/isIndeterminate 表达半选态。
  • toggleBehavior: 'single' 下展开行为类似手风琴——每次仅保留一个展开分支(findParentPath 重建路径)。
  • loop 默认 true(键盘焦点首尾循环),STree 与 STreeVirtualizer 均已在包装层镜像该默认,直接使用 Aria TreeRoot 时无需额外处理。
  • 虚拟滚动需要设置 height;STreeVirtualizer 的 item 插槽额外提供 virtualItem(用于 :data 透传与绝对定位样式)。
  • 展开/折叠时对移动子树做高度塌缩过渡动画。STreeVirtualizer 提供可选的 animated 属性,让可见项按普通文档流渲染(dynamic 模式),展开/折叠时无需绝对定位偏移即可保持项位置正确——默认关闭,因为动态测量对超大数据集开销更重;动画运行期间过渡列表会临时以完整文档流渲染,结束后恢复窗口化。
  • 节点文本完全由插槽提供,组件内无硬编码文案,因此无需本地化处理。

常见问题

如何实现可勾选(checkable)的树?

使用 multiple 多选 + 自定义 item 插槽渲染勾选图标,并消费 isSelected/isIndeterminate 状态:

<STree :items="items" multiple>
  <template #item="{ item, isSelected, isIndeterminate }">
    <STreeItem :value="item.value" :level="item.level">
      <SIcon :icon="isIndeterminate ? 'lucide:minus' : isSelected ? 'lucide:check-square' : 'lucide:square'" />
      {{ item.data.label }}
    </STreeItem>
  </template>
</STree>

需要「选中父级联动子孙」时叠加 propagateSelect,需要「子孙全选联动父级」时叠加 bubbleSelect。

如何控制树的展开状态?

受控:v-model:expanded="expandedKeys"(字符串数组);或非受控初始值 :default-expanded="['node-1']"。展开状态事件为 update:expanded。

大数据量下如何优化?

使用 STreeVirtualizer 并设置 height:仅渲染可视节点(配合自定义 options.estimateSize 控制行高),1000+ 节点仍保持流畅。

<STreeVirtualizer height="360px" :items="items">
  <template #item="{ item, virtualItem }">
    <STreeVirtualizerItem :value="item.value" :level="item.level" :data="virtualItem">
      {{ item.data.label }}
    </STreeVirtualizerItem>
  </template>
</STreeVirtualizer>

如何阻止选择父节点?

allowParentSelect 默认 false——点击含子节点的父项仅触发展开/折叠而不选中;需要选中父项时显式设置 :allow-parent-select="true"。

如何实现异步加载子节点?

组件未内置 loadData 契约,可在 toggle 事件中懒加载后更新 items:

<STree :items="items" @toggle="event => loadChildren(event.value)">
  <!-- item 插槽 -->
</STree>

加载完成后向 items 对应节点写入 children 即可(展开状态由 expanded 维护)。

如何自定义节点图标与缩进?

item 插槽自由组合:缩进用 item.level 计算 padding-left,图标按 item.hasChildren/isExpanded 切换,焦点态用 focus:ring-* 类名——参见演示 01。

键盘如何操作?

↑/↓ 在可见节点间移动焦点;→ 展开折叠节点(或进入子级)、← 折叠(或返回父级);Enter/Space 选中当前节点;连续输入字符触发 typeahead 定位;多选下 Shift + ↑/↓ 进行范围选择;loop 开启时首尾循环(默认开启)。

更新日志

版本记录按发布版本分组,便于快速查看这个组件在不同版本里的实际变更。

v0.50.0

2026-10-02

对比版本

新功能

添加基于状态的展开/折叠动画

范围: tree作者: soybeanfe查看提交7bc90

样式

将虚拟项传递给动画虚拟化器 motion 分支

范围: tree作者: soybeanfe查看提交a1bd2

样式

将虚拟化器的运动渲染裁剪至可见窗口内

范围: tree作者: soybeanfe查看提交da13e

样式

将 STree 项插槽 item 类型设为 FlattenedItem

范围: tree作者: soybeanfe查看提交8eb8b

样式

通过统一渲染列表,在虚拟化器移动过程中保持焦点

范围: tree作者: soybeanfe查看提交fb777

重构

移除展开时的自动动画过渡效果

范围: tree作者: soybeanfe查看提交afcc3

新功能

添加基于状态的展开/折叠动画

范围: tree作者: soybeanfe查看提交7bc90

修复

将虚拟项传递给动画虚拟化器 motion 分支

范围: tree作者: soybeanfe查看提交a1bd2

修复

将虚拟化器的运动渲染裁剪至可见窗口内

范围: tree作者: soybeanfe查看提交da13e

修复

将 STree 项插槽 item 类型设为 FlattenedItem

范围: tree作者: soybeanfe查看提交8eb8b

修复

通过统一渲染列表,在虚拟化器移动过程中保持焦点

范围: tree作者: soybeanfe查看提交fb777

重构

移除展开时的自动动画过渡效果

范围: tree作者: soybeanfe查看提交afcc3

v0.0.2

2025-11-18

对比版本

新功能

实现具有选择和展开行为的树形组件,包括用于增强功能的上下文和钩子

范围: tree作者: soybeanjs查看提交d6ab7

新功能

为树组件增强新的虚拟化功能,并重构现有结构以提升易用性

范围: tree作者: soybeanjs查看提交cf8e7

新功能

在 TreeRoot 组件中为键盘导航添加 loop 属性

范围: tree作者: soybeanjs查看提交e9f2a

新功能

为树组件增强选择行为和父节点路径查找功能

范围: tree作者: soybeanjs查看提交bb1ce

样式

从 Base 和 Virtualizer 的示例中移除 v-auto-animate 指令,以实现更简洁的代码

范围: tree作者: soybeanjs查看提交5b391

新功能

实现具有选择和展开行为的树形组件,包括用于增强功能的上下文和钩子

范围: tree作者: soybeanjs查看提交d6ab7

新功能

为树组件增强新的虚拟化功能,并重构现有结构以提升易用性

范围: tree作者: soybeanjs查看提交cf8e7

新功能

在 TreeRoot 组件中为键盘导航添加 loop 属性

范围: tree作者: soybeanjs查看提交e9f2a

新功能

为树组件增强选择行为和父节点路径查找功能

范围: tree作者: soybeanjs查看提交bb1ce

样式

从 Base 和 Virtualizer 的示例中移除 v-auto-animate 指令,以实现更简洁的代码

范围: tree作者: soybeanjs查看提交5b391