Tree v1.4.2
Introduction
MTree is a thin wrapper over Nuxt UI Tree, fully passing through all its props, events, and slots while adding several enhancements: search filtering with highlight, async lazy loading, a toolbar (expand/collapse toggle, tri-state select all), checkbox multi-select with parent/child strategy (cascade / isolated), key binding (v-model:selectedKeys), an imperative API, and selection categorization. Tree data normalization, filtering, and traversal reuse the Tree utility methods from @movk/core.
Usage
Pass items to render a hierarchical structure. Node defaultExpanded controls the initial expansion, and v-model binds the selected node:
<script setup lang="ts">
const items = ref([
{
label: 'app',
icon: 'i-lucide-folder',
defaultExpanded: true,
children: [
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
]
},
{
label: 'composables',
icon: 'i-lucide-folder',
children: [
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
]
}
])
const value = ref({ label: 'app.vue' })
</script>
<template>
<MTree v-model="value" :items="items" />
</template>
defaultExpanded Default Expansion
defaultExpanded derives the initially expanded parent nodes from a strategy, falling back to the node's own defaultExpanded flag. Pass true to expand all parents, a number to expand only parents with depth less than that value, or a function for custom logic per node and depth:
<script setup lang="ts">
const items = ref([
{
label: 'app',
icon: 'i-lucide-folder',
children: [
{
label: 'composables',
icon: 'i-lucide-folder',
children: [
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
]
},
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' }
]
},
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
])
</script>
<template>
<MTree :items="items" default-expanded />
</template>
searchable Search Filtering
searchable renders a search input at the top, prunes the tree by keyword while preserving ancestor chains for matching nodes. highlight is enabled by default, highlighting matched text and auto-expanding on match. filter allows a custom match predicate. search supports v-model:search two-way binding of the keyword:
<script setup lang="ts">
const items = ref([
{
label: 'app',
icon: 'i-lucide-folder',
children: [
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
]
},
{
label: 'components',
icon: 'i-lucide-folder',
children: [
{ label: 'Card.vue', icon: 'i-vscode-icons-file-type-vue' },
{ label: 'Button.vue', icon: 'i-vscode-icons-file-type-vue' }
]
}
])
</script>
<template>
<MTree :items="items" searchable />
</template>
checkable Checkbox Cascade
checkable renders a checkbox before each node, internally enables multiple with parent/child cascade and indeterminate state bubbling. v-model collects the selected node array. Checkboxes coexist with node icon and parent folder icons:
- app
- app.vue
- nuxt.config.ts
- composables
<script setup lang="ts">
const items = ref([
{
label: 'app',
icon: 'i-lucide-folder',
defaultExpanded: true,
children: [
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
]
},
{
label: 'composables',
icon: 'i-lucide-folder',
children: [
{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' },
{ label: 'useUser.ts', icon: 'i-vscode-icons-file-type-typescript' }
]
}
])
const value = ref([])
</script>
<template>
<MTree v-model="value" :items="items" checkable />
</template>
checkable is syntactic sugar for multiple + strategy (default cascade). Use multiple instead when you need multi-select without rendering checkboxes.multiple Multiple Selection
multiple enables multi-select without rendering checkboxes. Clicking a node accumulates the selection. v-model collects the selected node array:
<script setup lang="ts">
const items = ref([
{
label: 'Tech Center',
defaultExpanded: true,
children: [
{ label: 'Frontend', children: [{ label: 'Component Library' }, { label: 'Visualization' }] },
{ label: 'Backend' }
]
},
{ label: 'Product Center', children: [{ label: 'UX Design' }] }
])
const value = ref([])
</script>
<template>
<MTree v-model="value" :items="items" multiple />
</template>
strategy Parent/Child Strategy
strategy controls the parent/child check relationship in multi-select / checkable mode. cascade (default) cascades parent/child and re-fills the parent when all children are selected. isolated keeps parent and child independent — indeterminate state does not bubble:
- Tech Center
- Frontend
- Backend
<script setup lang="ts">
const items = ref([
{
label: 'Tech Center',
defaultExpanded: true,
children: [
{ label: 'Frontend', children: [{ label: 'Component Library' }, { label: 'Visualization' }] },
{ label: 'Backend', children: [{ label: 'Gateway' }, { label: 'Storage' }] }
]
}
])
const value = ref([])
</script>
<template>
<MTree v-model="value" :items="items" checkable strategy="cascade" />
</template>
selectedKeys Key Binding
selectedKeys two-way binds the selection using an array of node keys — useful for re-populating from the backend or syncing with routes. v-model:selectedKeys and v-model are interoperable. Keys are derived from getKey / labelKey:
- app
- app.vue
- nuxt.config.ts
<script setup lang="ts">
const items = ref([
{
label: 'app',
icon: 'i-lucide-folder',
defaultExpanded: true,
children: [
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
]
}
])
</script>
<template>
<MTree v-model:selected-keys="selectedKeys" :items="items" checkable />
</template>
toolbar Toolbar
toolbar renders a top toolbar with expand/collapse toggle buttons. When searchable is set, it embeds a clearable search input. When checkable is set, it adds a tri-state select-all checkbox and selection count:
- Tech Center
- Product Center
<script setup lang="ts">
const items = ref([
{
label: 'Tech Center',
children: [
{ label: 'Frontend', children: [{ label: 'Component Library' }, { label: 'Visualization' }] },
{ label: 'Backend', children: [{ label: 'Gateway' }, { label: 'Storage' }] }
]
},
{ label: 'Product Center', children: [{ label: 'UX Design' }, { label: 'User Research' }] }
])
const value = ref([])
</script>
<template>
<MTree v-model="value" :items="items" toolbar searchable checkable />
</template>
lazy Async Lazy Loading
lazy works with loadChildren — expanding an unloaded parent node fetches child nodes and displays a loading state. The isLeaf flag on a node marks it as a leaf, preventing expansion placeholder rendering:
<script setup lang="ts">
import type { TreeItem } from '@movk/nuxt'
const items: TreeItem[] = [
{ label: '区域 A' },
{ label: '区域 B' },
{ label: '直辖节点', isLeaf: true }
]
let seq = 0
function loadChildren(node: TreeItem): Promise<TreeItem[]> {
return new Promise(resolve => setTimeout(() => {
seq += 1
resolve([
{ label: `${node.label} / 子节点 ${seq}-1` },
{ label: `${node.label} / 子节点 ${seq}-2`, isLeaf: true }
])
}, 800))
}
</script>
<template>
<MTree :items="items" lazy :load-children="loadChildren" />
</template>
childrenKey Field Mapping
childrenKey normalizes the backend's child node field to children. labelKey specifies the display field, eliminating the need to pre-transform data structures:
<script setup lang="ts">
const items = ref([
{
name: 'Tech Center',
nodes: [
{ name: 'Frontend', nodes: [{ name: 'Component Library' }, { name: 'Visualization' }] },
{ name: 'Backend' }
]
},
{ name: 'Product Center', nodes: [{ name: 'UX Design' }] }
])
</script>
<template>
<MTree :items="items" children-key="nodes" label-key="name" />
</template>
labelKey Dot-Path Value Extraction
labelKey specifies the node display field, supporting dot-path deep extraction of nested fields like meta.title. Key derivation, search, and highlight all use the same path:
<script setup lang="ts">
const items = ref([
{
meta: { title: 'Tech Center' },
children: [
{
meta: { title: 'Frontend' },
children: [{ meta: { title: 'Component Library' } }, { meta: { title: 'Visualization' } }]
},
{ meta: { title: 'Backend' } }
]
},
{ meta: { title: 'Product Center' }, children: [{ meta: { title: 'UX Design' } }] }
])
</script>
<template>
<MTree :items="items" label-key="meta.title" searchable />
</template>
a.b.c) is supported — bracket notation (a[0].b) is not.virtualize Virtual Scrolling
virtualize passes through Nuxt UI Tree's virtualization capability, rendering only visible nodes — suitable for large data sets:
<script setup lang="ts">
import type { TreeItem } from '@movk/nuxt'
const items: TreeItem[] = Array.from({ length: 60 }, (_, group) => ({
label: `分组 ${group + 1}`,
defaultExpanded: group === 0,
children: Array.from({ length: 30 }, (_, leaf) => ({ label: `节点 ${group + 1}-${leaf + 1}` }))
}))
</script>
<template>
<MTree :items="items" :virtualize="true" class="max-h-72 w-md" />
</template>
color Primary Color
color passes through Nuxt UI Tree's primary color, applying to selected node text color and keyboard focus ring. The example pre-selects a node for visual reference:
<script setup lang="ts">
const items = ref([
{
label: 'app',
icon: 'i-lucide-folder',
defaultExpanded: true,
children: [
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
]
},
{
label: 'composables',
icon: 'i-lucide-folder',
children: [{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' }]
}
])
const value = ref({ label: 'app.vue' })
</script>
<template>
<MTree v-model="value" :items="items" color="error" />
</template>
color only applies to selected node text and focus ring. No visible change occurs when no node is selected. Single-color icons (e.g., lucide) inherit the text color; multi-color icons (e.g., vscode-icons) maintain their own coloring.trailingIcon Trailing Icon
trailingIcon replaces the expand indicator icon at the end of parent nodes (default i-lucide-chevron-down). item.trailingIcon on node data takes higher priority:
<script setup lang="ts">
const items = ref([
{
label: 'app',
icon: 'i-lucide-folder',
trailingIcon: 'i-lucide-arrow-down',
defaultExpanded: true,
children: [
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
]
},
{
label: 'composables',
icon: 'i-lucide-folder',
children: [{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' }]
}
])
</script>
<template>
<MTree :items="items" trailing-icon="i-lucide-chevron-right" />
</template>
expandedIcon Expand Icon
expandedIcon / collapsedIcon customize the leading icon for parent nodes when expanded / collapsed (default i-lucide-folder-open / i-lucide-folder):
<script setup lang="ts">
const items = ref([
{
label: 'app',
defaultExpanded: true,
children: [
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
]
},
{
label: 'composables',
children: [{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' }]
}
])
</script>
<template>
<MTree :items="items" expanded-icon="i-lucide-book-open" collapsed-icon="i-lucide-book" />
</template>
item.icon on a node takes higher priority than expandedIcon / collapsedIcon. Therefore, folders that need to switch icons based on expanded state should not set item.icon.disabled Disabled
disabled disables the entire tree, blocking click events on nodes, toolbar controls, and checkboxes for expand, collapse, and select operations. Per-node item.disabled disables that node and its entire subtree — freezing expansion state and disabling checkboxes within the subtree:
- app
- app.vue
- nuxt.config.ts
- composables
<script setup lang="ts">
const items = ref([
{
label: 'app',
icon: 'i-lucide-folder',
defaultExpanded: true,
children: [
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
]
},
{
label: 'composables',
icon: 'i-lucide-folder',
children: [{ label: 'useAuth.ts', icon: 'i-vscode-icons-file-type-typescript' }]
}
])
const value = ref([{ label: 'useAuth.ts' }])
</script>
<template>
<MTree v-model="value" :items="items" checkable toolbar disabled />
</template>
expandToDepth, selectAll, etc.) are explicit calls and are not affected by disabled. disabled only intercepts user clicks and toolbar interactions.Examples
Custom Node
Customize node content via passed-through slots like item-trailing. Uncovered slots are still rendered by Nuxt UI Tree's defaults:
<script setup lang="ts">
import type { TreeItem } from '@movk/nuxt'
const items: TreeItem[] = [
{
label: 'app',
icon: 'i-lucide-folder',
defaultExpanded: true,
children: [
{ label: 'app.vue', icon: 'i-vscode-icons-file-type-vue' },
{ label: 'nuxt.config.ts', icon: 'i-vscode-icons-file-type-nuxt' }
]
}
]
</script>
<template>
<MTree :items="items">
<template #item-trailing="{ item }">
<UBadge v-if="!item.children" label="file" color="neutral" variant="subtle" size="sm" />
</template>
</MTree>
</template>
Custom Toolbar
toolbar-leading / toolbar-trailing append content to the start/end of the default toolbar. Use the #toolbar slot for full control — its scope exposes methods and state like toggleExpand, selectAll, clear, and selectionSummary:
- 技术中心
- 产品中心
<script setup lang="ts">
import type { TreeItem } from '@movk/nuxt'
const items: TreeItem[] = [
{
label: '技术中心',
children: [
{ label: '前端组', children: [{ label: '组件库' }, { label: '可视化' }] },
{ label: '后端组', children: [{ label: '网关' }, { label: '存储' }] }
]
},
{ label: '产品中心', children: [{ label: '交互设计' }, { label: '用户研究' }] }
]
const checked = ref<TreeItem[]>([])
</script>
<template>
<MTree v-model="checked" :items="items" toolbar searchable checkable>
<template #toolbar-leading>
<UBadge label="部门" color="neutral" variant="subtle" size="sm" />
</template>
<template #toolbar-trailing>
<UBadge :label="`${checked.length} 项`" color="primary" variant="subtle" size="sm" />
</template>
</MTree>
</template>
Imperative Control
Obtain the component instance via useTemplateRef and call methods like expandToDepth, collapseAll, selectAll, and clearSelection to control the tree:
- 技术中心
- 产品中心
<script setup lang="ts">
import type { TreeExposed, TreeItem } from '@movk/nuxt'
const items: TreeItem[] = [
{
label: '技术中心',
children: [
{ label: '前端组', children: [{ label: '组件库' }, { label: '可视化' }] },
{ label: '后端组', children: [{ label: '网关' }, { label: '存储' }] }
]
},
{ label: '产品中心', children: [{ label: '交互设计' }, { label: '用户研究' }] }
]
const checked = ref<TreeItem[]>([])
const tree = useTemplateRef<TreeExposed>('tree')
</script>
<template>
<div class="space-y-3">
<div class="flex flex-wrap gap-2">
<UButton size="xs" label="展开到第 2 层" @click="tree?.expandToDepth(2)" />
<UButton size="xs" label="收起全部" color="neutral" variant="subtle" @click="tree?.collapseAll()" />
<UButton size="xs" label="全选" @click="tree?.selectAll()" />
<UButton size="xs" label="清空" color="neutral" variant="subtle" @click="tree?.clearSelection()" />
</div>
<MTree ref="tree" v-model="checked" :items="items" checkable />
</div>
</template>
Selection Categorization
The instance's reactive treeSelection returns selection categories: leaves (selected leaves), parents (fully selected parents), halfSelected (indeterminate parents), and strictlyChecked (excludes children selected via parent cascade):
- 技术中心
- 前端组
- 后端组
<script setup lang="ts">
import type { TreeExposed, TreeItem } from '@movk/nuxt'
const items: TreeItem[] = [
{
label: '技术中心',
defaultExpanded: true,
children: [
{ label: '前端组', children: [{ label: '组件库' }, { label: '可视化' }] },
{ label: '后端组', children: [{ label: '网关' }, { label: '存储' }] }
]
}
]
const checked = ref<TreeItem[]>([])
const tree = useTemplateRef<TreeExposed>('tree')
const labels = (nodes?: TreeItem[]) => (nodes ?? []).map(node => node.label).join('、') || '无'
</script>
<template>
<div class="space-y-3">
<MTree ref="tree" v-model="checked" :items="items" checkable />
<dl class="text-sm text-muted space-y-1">
<div>叶子(leaves):{{ labels(tree?.treeSelection.leaves) }}</div>
<div>满选父级(parents):{{ labels(tree?.treeSelection.parents) }}</div>
<div>半选父级(halfSelected):{{ labels(tree?.treeSelection.halfSelected) }}</div>
</dl>
</div>
</template>
API
Props
| Prop | Default | Type |
|---|---|---|
as | 'ul' | anyThe element or component this component should render as. |
items | T树数据源,按 childrenKey 解析层级 | |
childrenKey | 'children' | string取子节点数组的字段名,归一化为 UTree 的 children |
labelKey | 'label' | keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>展示字段名 |
getKey | (val: T[number]) => string自定义节点 key,缺省取 labelKey 字段值 | |
defaultExpanded | number | false | true | (node: T[number], depth: number): boolean初始展开策略,缺省回退节点上的 defaultExpanded 标记
| |
selectedKeys | string[]选中节点 key 列表,可用 v-model:selectedKeys 双向绑定 | |
multiple | M开启多选 | |
strategy | 'cascade' | "cascade" | "isolated"多选 / checkable 下的父子勾选策略
|
size | 'md' | "md" | "xs" | "sm" | "lg" | "xl"尺寸 |
color | 'primary' | "primary" | "secondary" | "info" | "success" | "warning" | "error" | "important" | "neutral"主色 |
expandedIcon | 取 app.config 的 ui.icons.folderOpen | any父节点展开时的图标 |
collapsedIcon | 取 app.config 的 ui.icons.folder | any父节点折叠时的图标 |
filter | TreeFilter<T[number]>自定义匹配谓词,缺省按 labelKey 文本不区分大小写包含匹配 | |
loadChildren | TreeLoadChildren<T[number]>懒加载回调,展开未加载的父节点时调用 | |
checkable | M渲染复选框并启用多选(multiple + strategy,默认 cascade) | |
trailingIcon | appConfig.ui.icons.chevronDown | anyThe icon displayed on the right side of a parent node. |
modelValue | M extends true ? T[number][] : T[number]The controlled value of the Tree. Can be bind as | |
defaultValue | M extends true ? T[number][] : T[number]The value of the Tree when initially rendered. Use when you do not need to control the state of the Tree. | |
virtualize | false | boolean | { overscan?: number; estimateSize?: number | ((index: number) => number); }Enable virtualization for large lists.
Note: when enabled, the tree structure is flattened like if |
onSelect | (e: SelectEvent<T[number]>, item: T[number]) => void | |
onToggle | (e: ToggleEvent<T[number]>, item: T[number]) => void | |
expanded | [] | string[]The controlled value of the expanded item. Can be binded with |
selectionBehavior | "replace" | "toggle"How multiple selection should behave in the collection. | |
search | '' | string |
propagateSelect | boolean选中父节点时级联选中子节点。cascade 策略下默认开启,显式 true 可在 isolated 下强制开启;关闭级联请用 strategy='isolated' | |
bubbleSelect | boolean子节点全部选中时回填父节点。cascade 策略下默认开启,显式 true 可在 isolated 下强制开启;关闭级联请用 strategy='isolated' | |
disabled | boolean禁用整棵树,阻断点击、工具栏与复选框的展开、折叠、选中 | |
searchable | boolean开启顶部搜索过滤 | |
highlight | true | boolean高亮命中文本,仅在 searchable 时生效 |
lazy | boolean开启异步懒加载子节点 | |
toolbar | boolean开启顶部工具栏(展开/折叠,checkable 时附带全选/清空) | |
nested | true | booleanUse nested DOM structure (children inside parents) vs flattened structure (all items at same level).
When |
ui | Record<string, ClassNameValue> & { root?: SlotClass; item?: SlotClass; listWithChildren?: SlotClass; itemWithChildren?: SlotClass; link?: SlotClass; linkLeadingIcon?: SlotClass; linkLabel?: SlotClass; linkTrailing?: SlotClass; linkTrailingIcon?: SlotClass; container?: SlotClass; toolbar?: SlotClass; toolbarButton?: SlotClass; search?: SlotClass; checkbox?: SlotClass; highlight?: SlotClass; loading?: SlotClass; loadingIcon?: SlotClass; empty?: SlotClass; } |
Emits
| Event | Type |
|---|---|
update:modelValue | [val: M extends true ? T[number][] : T[number]] |
update:expanded | [val: string[]] |
update:search | [value: string] |
change | [payload: { value: M extends true ? T[number][] : T[number]; keys: string[]; selection: TreeSelectionResult<T[number]>; }] |
update:selectedKeys | [value: string[]] |
update:modelValue and update:expanded, MTree additionally provides:update:search: Fires when the search keyword changes, supportsv-model:search.update:selectedKeys: Fires when the selected key list changes, supportsv-model:selectedKeys.change: Fires when the selection changes. Payload is{ value, keys, selection }.keysis derived fromgetKey/labelKey.selectionis the selection categorization result.
Slots
| Slot | Type |
|---|---|
item-wrapper | { item: T[number]; index: number; level: number; expanded: boolean; selected: boolean; indeterminate: boolean; handleSelect: () => void; handleToggle: () => void; ui: { root: (props?: Record<string, any>) => string; item: (props?: Record<string, any>) => string; listWithChildren: (props?: Record<string, any>) => string; itemWithChildren: (props?: Record<string, any>) => string; link: (props?: Record<string, any>) => string; linkLeadingIcon: (props?: Record<string, any>) => string; linkLabel: (props?: Record<string, any>) => string; linkTrailing: (props?: Record<string, any>) => string; linkTrailingIcon: (props?: Record<string, any>) => string; }; } |
item | { item: T[number]; index: number; level: number; expanded: boolean; selected: boolean; indeterminate: boolean; handleSelect: () => void; handleToggle: () => void; ui: { root: (props?: Record<string, any>) => string; item: (props?: Record<string, any>) => string; listWithChildren: (props?: Record<string, any>) => string; itemWithChildren: (props?: Record<string, any>) => string; link: (props?: Record<string, any>) => string; linkLeadingIcon: (props?: Record<string, any>) => string; linkLabel: (props?: Record<string, any>) => string; linkTrailing: (props?: Record<string, any>) => string; linkTrailingIcon: (props?: Record<string, any>) => string; }; } |
item-leading | { item: T[number]; index: number; level: number; expanded: boolean; selected: boolean; indeterminate: boolean; handleSelect: () => void; handleToggle: () => void; ui: { root: (props?: Record<string, any>) => string; item: (props?: Record<string, any>) => string; listWithChildren: (props?: Record<string, any>) => string; itemWithChildren: (props?: Record<string, any>) => string; link: (props?: Record<string, any>) => string; linkLeadingIcon: (props?: Record<string, any>) => string; linkLabel: (props?: Record<string, any>) => string; linkTrailing: (props?: Record<string, any>) => string; linkTrailingIcon: (props?: Record<string, any>) => string; }; } |
item-label | { item: T[number]; index: number; level: number; expanded: boolean; selected: boolean; indeterminate: boolean; handleSelect: () => void; handleToggle: () => void; ui: { root: (props?: Record<string, any>) => string; item: (props?: Record<string, any>) => string; listWithChildren: (props?: Record<string, any>) => string; itemWithChildren: (props?: Record<string, any>) => string; link: (props?: Record<string, any>) => string; linkLeadingIcon: (props?: Record<string, any>) => string; linkLabel: (props?: Record<string, any>) => string; linkTrailing: (props?: Record<string, any>) => string; linkTrailingIcon: (props?: Record<string, any>) => string; }; } |
item-trailing | { item: T[number]; index: number; level: number; expanded: boolean; selected: boolean; indeterminate: boolean; handleSelect: () => void; handleToggle: () => void; ui: { root: (props?: Record<string, any>) => string; item: (props?: Record<string, any>) => string; listWithChildren: (props?: Record<string, any>) => string; itemWithChildren: (props?: Record<string, any>) => string; link: (props?: Record<string, any>) => string; linkLeadingIcon: (props?: Record<string, any>) => string; linkLabel: (props?: Record<string, any>) => string; linkTrailing: (props?: Record<string, any>) => string; linkTrailingIcon: (props?: Record<string, any>) => string; }; } |
toolbar | { expandAll: () => void; collapseAll: () => void; toggleExpand: () => void; allExpanded: boolean; selectAll: () => void; clear: () => void; search: string; disabled?: boolean; selectionSummary: TreeSelectionSummary; } |
toolbar-leading | any默认工具栏起始处追加内容 |
toolbar-trailing | any默认工具栏末尾追加内容 |
empty | any |
loading | { node: T[number]; } |
Expose
You can access the typed component instance via useTemplateRef.
| Name | Type |
|---|---|
expandAll() | void Expand all expandable nodes |
collapseAll() | void Collapse all nodes |
expandToDepth(depth) | void Expand to the specified depth. |
selectAll() | void Select all selectable nodes |
clearSelection() | void Clear all selections |
treeSelection | TreeSelectionResult Current selection categorization ( |
Theme
export default defineAppConfig({
ui: {
tree: {
slots: {
container: 'flex flex-col gap-2 min-h-0',
toolbar: 'flex items-center gap-1.5',
toolbarButton: 'shrink-0',
search: 'flex-1 min-w-0',
checkbox: 'shrink-0 me-1.5',
highlight: 'rounded-[2px] bg-primary/15 text-primary',
loading: 'flex items-center gap-1.5 text-sm text-muted',
loadingIcon: 'size-4 shrink-0 animate-spin',
empty: 'py-6 text-center text-sm text-muted'
}
}
}
})