---
title: "列配置"
description: "数据列的固定、排序、列固定切换、列宽拖拽、文本截断、Tooltip、可见性与函数式配置。"
seo_title: "Columns"
seo_description: "Configure DataTable data columns — fixed columns, sorting, column pinning, resizing, text truncation, tooltips, visibility and functional (per-column) configuration."
canonical_url: "https://nuxt.mhaibaraai.cn/docs/data-table/columns"
---
# 列配置

> 数据列的固定、排序、列固定切换、列宽拖拽、文本截断、Tooltip、可见性与函数式配置。

## `fixed` 固定列

`column.fixed` 把列贴到表格两侧，横向滚动时保持可见：

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

const data = makePeople(8)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`

const columns: DataTableColumn<Person>[] = [
  { accessorKey: 'id', header: '工号', fixed: 'left', size: 100 },
  { accessorKey: 'name', header: '姓名', fixed: 'left', size: 120 },
  { accessorKey: 'role', header: '岗位' },
  { accessorKey: 'address', header: '地址' },
  { accessorKey: 'email', header: '邮箱' },
  { accessorKey: 'salary', header: '薪资', fixed: 'right', align: 'right', cell: moneyCell }
]
</script>

<template>
  <MDataTable :columns="columns" :data="data" :ui="{ root: 'max-w-2xl' }" />
</template>
```

## `children` 分组表头

通过 `children` 定义分组列（`DataTableGroupColumn`），形成多级表头：

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

const data = makePeople(6)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`

const columns: DataTableColumn<Person>[] = [
  { accessorKey: 'id', header: '工号' },
  {
    header: '员工信息',
    children: [
      { accessorKey: 'name', header: '姓名' },
      { accessorKey: 'department', header: '部门' },
      { accessorKey: 'role', header: '岗位' }
    ]
  },
  {
    header: '薪酬',
    children: [
      { accessorKey: 'level', header: '职级' },
      { accessorKey: 'salary', header: '薪资', align: 'right', cell: moneyCell }
    ]
  }
]
</script>

<template>
  <MDataTable :columns="columns" :data="data" bordered />
</template>
```

## `sortable` 列排序

全局 `sortable` 启用所有数据列点击表头排序；列级 `sortable` 反向覆盖单列（如 `sortable: false` 锁定不可排序）：

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

const data = makePeople(8)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`

const columns: DataTableColumn<Person>[] = [
  { accessorKey: 'id', header: '工号', sortable: true },
  { accessorKey: 'name', header: '姓名' },
  { accessorKey: 'level', header: '职级', sortable: false },
  { accessorKey: 'address', header: '地址' },
  { accessorKey: 'salary', header: '薪资', align: 'right', cell: moneyCell }
]
</script>

<template>
  <MDataTable :columns="columns" :data="data" />
</template>
```

## `pinable` 列固定切换

全局 `pinable` 让用户点表头图钉在 `left`、`right`、`none` 间循环；列级 `pinable` 优先级更高，可锁住强制位：

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

const data = makePeople(8)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`

const columns: DataTableColumn<Person>[] = [
  { accessorKey: 'id', header: '工号', fixed: 'left', pinable: true },
  { accessorKey: 'name', header: '姓名' },
  { accessorKey: 'department', header: '部门', pinable: false },
  { accessorKey: 'role', header: '岗位' },
  { accessorKey: 'salary', header: '薪资', align: 'right', cell: moneyCell }
]
</script>

<template>
  <MDataTable :columns="columns" :data="data" :ui="{ root: 'max-w-3xl' }" />
</template>
```

## `resizable` 列宽拖拽

全局 `resizable` 给所有数据列加拖拽手柄；列级 `resizable: false` 锁定单列宽度。`columnResizeMode` 控制 `onChange`（拖动中实时重排）或 `onEnd`（释放后更新）：

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

const data = makePeople(8)

const columns: DataTableColumn<Person>[] = [
  { accessorKey: 'id', header: '工号' },
  { accessorKey: 'name', header: '姓名', minSize: 80 },
  { accessorKey: 'level', header: '职级', resizable: false },
  { accessorKey: 'address', header: '地址', size: 120 },
  { accessorKey: 'bio', header: '个人简介', size: 150, resizable: true }
]
</script>

<template>
  <MDataTable :columns="columns" :data="data" :ui="{ root: 'max-w-3xl' }" />
</template>
```

## `size` / `minSize` / `maxSize` 列宽

`size` 设定固定列宽（数值或预设 `xs`–`xl`）。不设 `size` 而仅给 `minSize` / `maxSize` 时，列宽由内容自适应：`minSize` 是自适应与拖拽的下限；`maxSize` 是可拖拽到的最大宽度。已设 `size` 的列会被 `minSize` / `maxSize` 双向收敛。

```ts
const columns: DataTableColumn<Person>[] = [
  { accessorKey: 'name', header: '姓名', minSize: 120 },    // 自适应，不小于 120
  { accessorKey: 'bio', header: '简介', maxSize: 240 },     // 自适应，拖拽不超过 240
  { accessorKey: 'id', header: '工号', size: 'sm' }         // 固定预设宽 120
]
```

> \[\!NOTE\]
> 
> 表格采用 
> 
> table-layout: auto
> 
>  并撑满容器，自适应列的内容宽度可能超过 
> 
> maxSize
> 
> （auto 布局忽略单元格 
> 
> max-width
> 
> ）。因此对自适应列，
> 
> maxSize
> 
>  仅约束拖拽上限；要严格固定列宽请改用 
> 
> size
> 
> 。

> \[\!NOTE\]
> 
> 固定列（
> 
> fixed
> 
> ）需要确定宽度参与 sticky 偏移计算，因此默认固定为 
> 
> size
> 
> 。仅当某一侧只有一个固定列（贴近滚动区的内侧固定列）时，该列才支持按内容自适应——此时设 
> 
> minSize
> 
>  / 
> 
> maxSize
> 
>  即可让它随内容撑开（典型如右侧唯一的操作列）。

## 文本截断与 Tooltip

`truncate` 控制纯截断（`true` 单行 / `number` 多行 / `false` 禁用 / 函数动态）；`tooltip` 自带相同行数的截断，并在溢出时浮出完整内容。两者不需同时配置：

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

const data = makePeople(8)

const columns: DataTableColumn<Person>[] = [
  { accessorKey: 'name', header: '姓名' },
  { accessorKey: 'bio', header: '个人简介', size: 240, tooltip: 1 },
  { accessorKey: 'role', header: '角色', size: 60 },
  { accessorKey: 'address', header: '地址', size: 200, truncate: true }
]
</script>

<template>
  <MDataTable :columns="columns" :data="data" :ui="{ root: 'max-w-3xl' }" />
</template>
```

## 列可见性

`column.visibility` 设默认显隐；`columnVisibilityKeys`（白名单）与 `columnVisibilityExcludeKeys`（黑名单）互斥，同传时白名单优先：

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

const data = makePeople(6)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`
const columns: DataTableColumn<Person>[] = [
  { accessorKey: 'id', header: '工号' },
  { accessorKey: 'name', header: '姓名' },
  { accessorKey: 'department', header: '部门' },
  { accessorKey: 'role', header: '岗位' },
  { accessorKey: 'level', header: '职级' },
  { accessorKey: 'email', header: '邮箱' },
  { accessorKey: 'joinedAt', header: '入职日期', visibility: false },
  { accessorKey: 'salary', header: '薪资', align: 'right', cell: moneyCell }
]
</script>

<template>
  <MDataTable :columns="columns" :data="data" />
</template>
```

## 函数式配置

`sortable`、`pinable`、`resizable` 接受 `(col) => boolean`，`truncate`、`tooltip` 接受 `(ctx) => boolean | number`，一次声明替代逐列布尔，并可按字段或单元格上下文动态决定：

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

const data = makePeople(8)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`

const columns: DataTableColumn<Person>[] = [
  { accessorKey: 'id', header: '工号' },
  { accessorKey: 'name', header: '姓名' },
  { accessorKey: 'department', header: '部门' },
  { accessorKey: 'bio', header: '个人简介' },
  { accessorKey: 'address', header: '地址', size: 200 },
  { accessorKey: 'salary', header: '薪资', align: 'right', cell: moneyCell }
]

const sortableFn: DataTableProps<Person>['sortable'] = col => col.accessorKey !== 'id'
const pinableFn: DataTableProps<Person>['pinable'] = col => !['bio', 'address'].includes(col.accessorKey)
const resizableFn: DataTableProps<Person>['resizable'] = col => col.accessorKey !== 'salary'
const truncateFn: DataTableDataColumn<Person>['truncate'] = ctx =>
  ctx.column.id === 'bio' ? (ctx.row.original.bio.length > 45 ? 3 : 2) : true
const tooltipFn: DataTableDataColumn<Person>['tooltip'] = ctx => ctx.column.id === 'address'
</script>

<template>
  <MDataTable
    :columns="columns"
    :data="data"
    :sortable="sortableFn"
    :pinable="pinableFn"
    :resizable="resizableFn"
    :truncate="truncateFn"
    :tooltip="tooltipFn"
  />
</template>
```

> \[\!TIP\]
> 
> 列级 prop 优先级始终高于全局 prop。推荐用「全局开 + 个别列关」或「全局关 + 个别列开」的对照方式表达差异。

## 表头与单元格插槽

除了在 `columns` 里配置 `header` / `cell`，也可以按列 id 使用插槽渲染。列 id 即数据列的 `accessorKey`，特殊列则是 `__selection`、`__index`、`__expand`、`__row_pinning`、`__actions`：

| 插槽                 | 作用域类型                       | 说明        |
| ------------------ | --------------------------- | --------- |
| `#<column>-header` | `HeaderContext<T, unknown>` | 替换该列表头标签  |
| `#<column>-cell`   | `CellContext<T, unknown>`   | 替换该列单元格内容 |
| `#<column>-footer` | `HeaderContext<T, unknown>` | 替换该列表尾内容  |

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

const data = makePeople(6)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`

const columns: DataTableColumn<Person>[] = [
  { accessorKey: 'id', header: '工号', size: 100 },
  { accessorKey: 'name', header: '姓名', size: 140, sortable: true },
  { accessorKey: 'department', header: '部门', size: 120 },
  { accessorKey: 'level', header: '职级', size: 120 },
  { accessorKey: 'salary', header: '薪资', align: 'right', size: 140, cell: moneyCell }
]
</script>

<template>
  <MDataTable :columns="columns" :data="data">
    <template #name-header>
      <span class="inline-flex items-center gap-1 truncate">
        <UIcon name="i-lucide-user-round" class="size-4 text-primary" />
        姓名
      </span>
    </template>

    <template #department-cell="{ row }">
      <UBadge color="neutral" variant="subtle" size="sm">
        {{ row.original.department }}
      </UBadge>
    </template>

    <template #level-cell="{ getValue }">
      <UBadge v-if="getValue()" color="primary" variant="soft" size="sm">
        {{ getValue() }}
      </UBadge>
      <span v-else class="text-muted">未定级</span>
    </template>
  </MDataTable>
</template>
```

> \[\!NOTE\]
> 
> #<column>-header
> 
>  只替换
> 
> 标签位
> 
> ，
> 
> sortable
> 
> 、
> 
> pinable
> 
> 、
> 
> resizable
> 
>  生成的排序按钮、图钉按钮与列宽拖拽手柄仍会保留在表头内，无需自行渲染。

> \[\!WARNING\]
> 
> #<column>-cell
> 
>  整体替换单元格内容，该列的 
> 
> truncate
> 
> 、
> 
> tooltip
> 
> 、
> 
> emptyCell
> 
>  不再生效，需要时请在插槽内自行处理。分组表头（
> 
> children
> 
> ）的 id 由 TanStack 内部拼接，不支持插槽覆写，请用 
> 
> header
> 
>  配置。


## Sitemap

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