树形数据
通过 childrenKey 启用树形表格,配置展开、级联选择策略、缩进与选中结果读取。
树形数据基础
设置 children-key 即启用树形模式,配合 row-key 派生行 id、expand 列渲染折叠按钮。父级缺失字段(如职级)可由 emptyCell 占位:
| 成员 | 部门 | 岗位 | 职级 | |
|---|---|---|---|---|
李勇 | 产品 | 团队负责人 | — | |
王超 | 市场 | 团队负责人 | — | |
陈娜 | 设计 | 团队负责人 | — |
<script setup lang="ts">
import type { DataTableColumn } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const treeData = makePeopleTree(3, 3, 2)
const columns: DataTableColumn<Person>[] = [
{ type: 'expand' },
{ accessorKey: 'name', header: '成员' },
{ accessorKey: 'department', header: '部门' },
{ accessorKey: 'role', header: '岗位' },
{ accessorKey: 'level', header: '职级', emptyCell: '—' }
]
</script>
<template>
<MDataTable :data="treeData" :columns="columns" children-key="children" row-key="id" :ui="{ root: 'max-h-[50vh]' }" />
</template>
strategy 级联选择策略
selection 列的 strategy 决定父子勾选联动:cascade 父子级联、isolated 父子独立、leaf 仅叶子可勾(父节点展示为子孙派生态):
| 成员 | 部门 | 岗位 | ||
|---|---|---|---|---|
李勇 | 产品 | 团队负责人 | ||
王超 | 市场 | 团队负责人 | ||
陈娜 | 设计 | 团队负责人 |
<script setup lang="ts">
import type { DataTableColumn, DataTableSelectionColumn } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const treeData = makePeopleTree(3, 3, 2)
const strategy = ref<DataTableSelectionColumn['strategy']>('cascade')
const columns = computed<DataTableColumn<Person>[]>(() => [
{ type: 'selection', strategy: strategy.value },
{ type: 'expand' },
{ accessorKey: 'name', header: '成员' },
{ accessorKey: 'department', header: '部门' },
{ accessorKey: 'role', header: '岗位' }
])
</script>
<template>
<div class="flex flex-col gap-3">
<USelect
v-model="strategy"
:items="[
{ label: 'cascade 父子级联', value: 'cascade' },
{ label: 'isolated 父子独立', value: 'isolated' },
{ label: 'leaf 仅叶子可勾', value: 'leaf' }
]"
value-key="value"
size="xs"
class="w-56"
/>
<MDataTable :data="treeData" :columns="columns" children-key="children" row-key="id" />
</div>
</template>
mode 单选与多选
mode: 'single' 时整树仅单行勾选(通常配合 isolated);multiple 时配合 strategy 联动:
| 成员 | 部门 | 岗位 | ||
|---|---|---|---|---|
李勇 | 产品 | 团队负责人 | ||
王超 | 市场 | 团队负责人 | ||
陈娜 | 设计 | 团队负责人 |
<script setup lang="ts">
import type { DataTableColumn, DataTableSelectionColumn } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const treeData = makePeopleTree(3, 3, 2)
const mode = ref<DataTableSelectionColumn['mode']>('multiple')
const columns = computed<DataTableColumn<Person>[]>(() => [
{ type: 'selection', mode: mode.value, strategy: mode.value === 'single' ? 'isolated' : 'cascade' },
{ type: 'expand' },
{ accessorKey: 'name', header: '成员' },
{ accessorKey: 'department', header: '部门' },
{ accessorKey: 'role', header: '岗位' }
])
</script>
<template>
<div class="flex flex-col gap-3">
<USwitch
:model-value="mode === 'single'"
label="single 单选"
@update:model-value="mode = $event ? 'single' : 'multiple'"
/>
<MDataTable :data="treeData" :columns="columns" children-key="children" row-key="id" />
</div>
</template>
选中结果读取
v-model:row-selection-keys 双向同步选中 id 数组;组件 expose 的 treeSelection 派生 leaves、parents、halfSelected、strictlyChecked 四类业务视图,并提供 clearSelection():
| 成员 | 部门 | ||
|---|---|---|---|
李勇 | 产品 | ||
王超 | 市场 | ||
陈娜 | 设计 |
{}<script setup lang="ts">
import type { DataTableColumn, DataTableExposed } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const treeData = makePeopleTree(3, 3, 2)
const tableRef = useTemplateRef<DataTableExposed<Person>>('tableRef')
const selectionKeys = ref<string[]>([])
const names = (rows: Person[]) => rows.map(p => p.name)
const result = computed(() => {
const r = tableRef.value?.treeSelection
if (!r) return {}
return {
selectionKeys: selectionKeys.value,
leaves: names(r.leaves),
parents: names(r.parents),
halfSelected: names(r.halfSelected),
strictlyChecked: names(r.strictlyChecked)
}
})
const columns: DataTableColumn<Person>[] = [
{ type: 'selection', strategy: 'cascade' },
{ type: 'expand' },
{ accessorKey: 'name', header: '成员' },
{ accessorKey: 'department', header: '部门' }
]
</script>
<template>
<div class="flex flex-col gap-3">
<UButton size="xs" variant="soft" class="self-start" @click="tableRef?.clearSelection()">
清空选中
</UButton>
<MDataTable
ref="tableRef"
v-model:row-selection-keys="selectionKeys"
:data="treeData"
:columns="columns"
children-key="children"
row-key="id"
/>
<pre class="text-xs p-3 rounded-md bg-muted overflow-auto">{{ result }}</pre>
</div>
</template>
indentSize 树形缩进
indentSize 支持字符串、数字(px)与函数三种形态,函数形态可按 row.depth 等上下文动态调整:
| 成员 | 部门 | 岗位 | |
|---|---|---|---|
李勇 | 产品 | 团队负责人 | |
王超 | 市场 | 团队负责人 | |
陈娜 | 设计 | 团队负责人 |
<script setup lang="ts">
import type { DataTableColumn } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const treeData = makePeopleTree(3, 3, 3)
const columns: DataTableColumn<Person>[] = [
{ type: 'expand' },
{ accessorKey: 'name', header: '成员' },
{ accessorKey: 'department', header: '部门' },
{ accessorKey: 'role', header: '岗位' }
]
</script>
<template>
<MDataTable :data="treeData" :columns="columns" children-key="children" row-key="id" />
</template>
展开行为控制
expand 列的 buttonProps 与 toggleAllButtonProps 分别定制单元格与表头按钮(接收 isExpanded/isAllExpanded);expand-on-row-click 整行触发展开;expose 的 expandToDepth(n) 按层展开、collapseAll() 收起全部,v-model:expanded-keys 同步展开 id:
| 成员 | 部门 | 岗位 | |
|---|---|---|---|
李勇 | 产品 | 团队负责人 | |
王超 | 市场 | 团队负责人 | |
陈娜 | 设计 | 团队负责人 |
<script setup lang="ts">
import type { DataTableColumn, DataTableExposed } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const treeData = makePeopleTree(3, 3, 3)
const tableRef = useTemplateRef<DataTableExposed<Person>>('tableRef')
const expandOnRowClick = ref(false)
const columns: DataTableColumn<Person>[] = [
{
type: 'expand',
buttonProps: ctx => ({
icon: ctx.isExpanded ? 'i-lucide-folder-open' : 'i-lucide-folder',
color: ctx.isExpanded ? 'primary' : 'neutral',
variant: 'soft'
}),
toggleAllButtonProps: ctx => ({
icon: ctx.isAllExpanded ? 'i-lucide-chevrons-down-up' : 'i-lucide-chevrons-up-down',
variant: 'soft',
color: 'primary'
})
},
{ accessorKey: 'name', header: '成员' },
{ accessorKey: 'department', header: '部门' },
{ accessorKey: 'role', header: '岗位' }
]
</script>
<template>
<div class="flex flex-col gap-3">
<div class="flex flex-wrap items-center gap-2">
<USwitch v-model="expandOnRowClick" label="expandOnRowClick" />
<UButton size="xs" variant="soft" @click="tableRef?.expandToDepth(1)">
展开 1 级
</UButton>
<UButton size="xs" variant="soft" @click="tableRef?.expandToDepth(2)">
展开 2 级
</UButton>
<UButton size="xs" variant="soft" @click="tableRef?.collapseAll()">
收起全部
</UButton>
</div>
<MDataTable
ref="tableRef"
:data="treeData"
:columns="columns"
children-key="children"
row-key="id"
:expand-on-row-click="expandOnRowClick"
/>
</div>
</template>