---
title: "树形数据"
description: "通过 childrenKey 启用树形表格，配置展开、级联选择策略、缩进与选中结果读取。"
seo_title: "Tree Data"
seo_description: "Render hierarchical data in DataTable via childrenKey — expand column, cascade/isolated/leaf selection strategies, single/multiple mode, indentation and tree selection result."
canonical_url: "https://nuxt.mhaibaraai.cn/docs/data-table/tree"
---
# 树形数据

> 通过 childrenKey 启用树形表格，配置展开、级联选择策略、缩进与选中结果读取。

## 树形数据基础

设置 `children-key` 即启用树形模式，配合 `row-key` 派生行 id、`expand` 列渲染折叠按钮。父级缺失字段（如职级）可由 `emptyCell` 占位：

```vue [DataTableTreeBasicExample.vue]
<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` 仅叶子可勾（父节点展示为子孙派生态）：

```vue [DataTableTreeStrategyExample.vue]
<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` 联动：

```vue [DataTableTreeModeExample.vue]
<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()`：

```vue [DataTableTreeResultExample.vue]
<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` 等上下文动态调整：

```vue [DataTableTreeIndentExample.vue]
<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 :default-expanded="1" :data="treeData" :columns="columns" children-key="children" row-key="id" />
</template>
```

## `defaultExpanded` 默认展开

`default-expanded` 在未提供 `expanded` / `expanded-keys`（受控优先）时决定初始展开：`true` 展开全部父级行、`number` 展开 `depth` 小于该值的父级行（与 `expandToDepth(n)` 同义）、函数 `(row, depth) => boolean` 按行与深度自定义，无需手写收集父级 id：

```vue [DataTableTreeDefaultExpandExample.vue]
<script setup lang="ts">
import type { DataTableColumn, DataTableProps } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'

const props = withDefaults(defineProps<{
  mode?: 'all' | 'depth1' | 'depth2' | 'fn'
}>(), { mode: 'all' })

const treeData = makePeopleTree(3, 3, 3)

const columns: DataTableColumn<Person>[] = [
  { type: 'expand' },
  { accessorKey: 'name', header: '成员' },
  { accessorKey: 'department', header: '部门' },
  { accessorKey: 'role', header: '岗位' }
]

const defaultExpanded = computed<DataTableProps<Person>['defaultExpanded']>(() => {
  if (props.mode === 'depth1') return 1
  if (props.mode === 'depth2') return 2
  if (props.mode === 'fn') return row => row.department === '设计'
  return true
})
</script>

<template>
  <MDataTable
    :key="props.mode"
    :default-expanded="defaultExpanded"
    :data="treeData"
    :columns="columns"
    children-key="children"
    row-key="id"
    class="max-h-150"
  />
</template>
```

## 展开行为控制

`expand` 列的 `buttonProps` 与 `toggleAllButtonProps` 分别定制单元格与表头按钮（接收 `isExpanded`/`isAllExpanded`）；`expand-on-row-click` 整行触发展开；expose 的 `expandToDepth(n)` 按层展开、`collapseAll()` 收起全部，`v-model:expanded-keys` 同步展开 id：

```vue [DataTableTreeExpandExample.vue]
<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>
```


## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
