ProTable 高级表格
基于 NDataTable 封装,支持搜索栏、分页、批量操作、列配置、远程数据、自定义渲染。
基础用法
基础表格
静态数据 + 分页 + 自定义状态列渲染。
vue
<script setup lang="ts">
import type { ProTableColumn } from '@naive-ui-pro/pro-table'
import { ProTable } from '@naive-ui-pro/pro-table'
import { NTag } from 'naive-ui'
import { h, ref } from 'vue'
const columns: ProTableColumn[] = [
{ title: '姓名', key: 'name' },
{ title: '年龄', key: 'age' },
{
title: '状态',
key: 'status',
render(row: any) {
return h(NTag, {
type: row.status === 1 ? 'success' : 'warning',
size: 'small',
}, { default: () => row.status === 1 ? '启用' : '禁用' })
},
},
{ title: '部门', key: 'department' },
{ title: '角色', key: 'role' },
{ title: '邮箱', key: 'email', ellipsis: { tooltip: true } },
{ title: '地址', key: 'address' },
{ title: '创建时间', key: 'createdAt' },
]
const data = ref([
{ id: 1, name: '张三', age: 32, status: 1, department: '研发部', role: '前端工程师', email: 'zhangsan@example.com', address: '北京市朝阳区', createdAt: '2026-06-01' },
{ id: 2, name: '李四', age: 28, status: 0, department: '产品部', role: '产品经理', email: 'lisi@example.com', address: '上海市浦东新区', createdAt: '2026-05-18' },
{ id: 3, name: '王五', age: 45, status: 1, department: '运营部', role: '运营主管', email: 'wangwu@example.com', address: '广州市天河区', createdAt: '2026-04-12' },
{ id: 4, name: '赵六', age: 36, status: 1, department: '设计部', role: 'UI 设计师', email: 'zhaoliu@example.com', address: '深圳市南山区', createdAt: '2026-03-08' },
])
</script>
<template>
<ProTable title="高级表格" :columns="columns" :data="data" :pagination="{ pageSize: 10 }" :option="{ header: false }" />
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
搜索 + 批量操作
搜索栏 + 批量操作
columns 配置 search 启用搜索,batchActions 配置批量操作按钮。
vue
<script setup lang="ts">
import type { ProTableBatchAction, ProTableColumn, ProTableRequestResult } from '@naive-ui-pro/pro-table'
import { ProTable } from '@naive-ui-pro/pro-table'
import { useMessage } from 'naive-ui'
import { ref } from 'vue'
const message = useMessage()
const columns: ProTableColumn[] = [
{
title: '姓名',
key: 'name',
search: {
component: 'input',
label: '姓名',
},
},
{
title: '年龄',
key: 'age',
search: {
component: 'input-number',
label: '年龄',
props: { min: 0, max: 150 },
},
},
{
title: '状态',
key: 'status',
search: {
component: 'select',
label: '状态',
options: [{ label: '启用', value: 1 }, { label: '禁用', value: 0 }],
},
},
{
title: '部门',
key: 'department',
search: {
component: 'select',
options: [{ label: '研发部', value: '研发部' }, { label: '产品部', value: '产品部' }, { label: '运营部', value: '运营部' }],
},
},
{
title: '邮箱',
key: 'email',
search: true,
},
{
title: '手机号',
key: 'phone',
},
{
title: '地址',
key: 'address',
search: {
component: 'input',
label: '地址',
},
},
{
title: '创建时间',
key: 'createdAt',
},
]
const allData = Array.from({ length: 100 }, (_, i) => ({
id: i + 1,
name: ['张三', '李四', '王五', '赵六', '钱七', '孙八'][i % 6],
age: 20 + (i % 40),
status: i % 3 === 0 ? 0 : 1,
department: ['研发部', '产品部', '运营部'][i % 3],
email: `user${i + 1}@example.com`,
phone: `1380000${String(i).padStart(4, '0')}`,
address: ['北京', '上海', '广州', '深圳', '杭州', '成都'][i % 6],
createdAt: `2026-06-${String((i % 28) + 1).padStart(2, '0')}`,
}))
async function request(params: Record<string, unknown>): Promise<ProTableRequestResult> {
await new Promise(r => setTimeout(r, 300))
let filtered = [...allData]
if (params.name)
filtered = filtered.filter(r => (r.name as string).includes(params.name as string))
if (params.status !== undefined && params.status !== null)
filtered = filtered.filter(r => r.status === params.status)
if (params.department)
filtered = filtered.filter(r => r.department === params.department)
if (params.email)
filtered = filtered.filter(r => r.email.includes(params.email as string))
if (params.address)
filtered = filtered.filter(r => (r.address as string).includes(params.address as string))
const page = (params.current as number) || 1
const pageSize = (params.size as number) || 10
return { data: filtered.slice((page - 1) * pageSize, page * pageSize), total: filtered.length }
}
const checkedKeys = ref<(string | number)[]>([])
const batchActions: ProTableBatchAction[] = [
{
key: 'delete',
label: '批量删除',
type: 'error',
onClick(keys) {
message.success(`删除 ${keys.length} 项`)
checkedKeys.value = []
},
},
{
key: 'export',
label: '导出',
type: 'info',
onClick(keys) {
message.success(`导出 ${keys.length} 项`)
},
},
]
</script>
<template>
<ProTable
v-model:checked-row-keys="checkedKeys"
:columns="columns"
:request="request"
:batch-actions="batchActions"
/>
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
全部搜索组件
搜索组件实验台
一次展示 input、input-number、select、date-picker、cascader、tree-select、switch、radio-group、checkbox-group 与 render。
vue
<script setup lang="ts">
import type { ProTableColumn } from '@naive-ui-pro/pro-table'
import { ProTable } from '@naive-ui-pro/pro-table'
import { NInput } from 'naive-ui'
import { h } from 'vue'
const columns: ProTableColumn[] = [
{ title: '关键词', key: 'keyword', search: { component: 'input', placeholder: 'Input' } },
{ title: '数量', key: 'count', search: { component: 'input-number', min: 0 } },
{ title: '状态', key: 'status', search: { component: 'select', options: [{ label: '启用', value: 1 }, { label: '停用', value: 0 }] } },
{ title: '日期', key: 'date', search: { component: 'date-picker', type: 'date', clearable: true } },
{ title: '地区', key: 'region', search: { component: 'cascader', options: [{ label: '华北', value: 'north', children: [{ label: '北京', value: 'beijing' }] }] } },
{ title: '组织', key: 'org', search: { component: 'tree-select', options: [{ label: '研发中心', key: 'rd', children: [{ label: '前端组', key: 'frontend' }] }] } },
{ title: '公开', key: 'visible', search: { component: 'switch', checkedText: '是', uncheckedText: '否' } },
{ title: '类型', key: 'type', search: { component: 'radio-group', options: [{ label: '内部', value: 'internal' }, { label: '外部', value: 'external' }] } },
{ title: '标签', key: 'tags', search: { component: 'checkbox-group', options: [{ label: '重点', value: 'important' }, { label: '待办', value: 'todo' }] } },
{ title: '自定义', key: 'custom', search: { component: 'render', render: props => h(NInput, { ...props, placeholder: 'Render 自定义控件' }) } },
]
const data = [{ id: 1, keyword: '示例数据', count: 12, status: 1, date: '2026-07-19', region: '北京', org: '前端组', visible: true, type: 'internal', tags: '重点', custom: '-' }]
</script>
<template>
<ProTable
:columns="columns"
:data="data"
:pagination="false"
:option="{ manualSearch: true, tableHeader: false }"
/>
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
远程数据
远程请求 + 排序
通过 request 函数获取远程数据,支持服务端排序和分页。
vue
<script setup lang="ts">
import type { ProTableColumn, ProTableRequestResult } from '@naive-ui-pro/pro-table'
import { ProTable } from '@naive-ui-pro/pro-table'
import { NButton, NSpace, NTag } from 'naive-ui'
import { h } from 'vue'
const columns: ProTableColumn[] = [
{ title: 'ID', key: 'id', width: 60 },
{ title: '姓名', key: 'name' },
{ title: '年龄', key: 'age', sorter: true },
{
title: '状态',
key: 'status',
render(row: any) {
return h(NTag, {
type: row.status === 1 ? 'success' : 'warning',
size: 'small',
}, { default: () => row.status === 1 ? '启用' : '禁用' })
},
},
{ title: '部门', key: 'department' },
{ title: '邮箱', key: 'email', ellipsis: { tooltip: true } },
{ title: '地址', key: 'address', ellipsis: { tooltip: true } },
{ title: '创建时间', key: 'createdAt' },
{
title: '操作',
key: 'actions',
render() {
return h(NSpace, { size: 'small' }, {
default: () => [
h(NButton, { size: 'tiny', type: 'primary', quaternary: true }, { default: () => '编辑' }),
h(NButton, { size: 'tiny', type: 'error', quaternary: true }, { default: () => '删除' }),
],
})
},
},
]
const allData = Array.from({ length: 50 }, (_, i) => ({
id: i + 1,
name: ['张三', '李四', '王五', '赵六', '钱七', '孙八'][i % 6],
age: 20 + (i % 40),
status: i % 3 === 0 ? 0 : 1,
department: ['研发部', '产品部', '运营部', '设计部'][i % 4],
email: `user${i + 1}@example.com`,
address: ['北京市朝阳区建国路88号', '上海市浦东新区陆家嘴环路1000号', '广州市天河区天河路385号', '深圳市南山区科技园南路'][i % 4],
createdAt: `2026-05-${String((i % 28) + 1).padStart(2, '0')}`,
}))
async function request(params: Record<string, unknown>): Promise<ProTableRequestResult> {
await new Promise(r => setTimeout(r, 500))
const filtered = [...allData]
const page = (params.current as number) || 1
const pageSize = (params.size as number) || 10
const orderBy = params.orderBy as string
if (orderBy) {
const [field, order] = orderBy.split(' ')
filtered.sort((a: any, b: any) => order === 'asc' ? a[field] - b[field] : b[field] - a[field])
}
return {
data: filtered.slice((page - 1) * pageSize, page * pageSize),
total: filtered.length,
}
}
</script>
<template>
<ProTable :columns="columns" :request="request" :pagination="{ pageSize: 10 }" />
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
列配置
列配置与固定列
更多列、横向滚动、左右固定和列设置。
vue
<script setup lang="ts">
import type { ProTableColumn } from '@naive-ui-pro/pro-table'
import { ProTable } from '@naive-ui-pro/pro-table'
const columns: ProTableColumn[] = [
{ title: '姓名', key: 'name', fixed: 'left', width: 120 },
{ title: '年龄', key: 'age', width: 100 },
{ title: '部门', key: 'department', width: 140 },
{ title: '角色', key: 'role', width: 160 },
{ title: '邮箱', key: 'email', width: 220 },
{ title: '手机号', key: 'phone', width: 160 },
{ title: '地址', key: 'address', width: 240 },
{ title: '操作', key: 'action', fixed: 'right', width: 120 },
]
const data = [
{ id: 1, name: '张三', age: 32, department: '研发部', role: '前端工程师', email: 'zhangsan@example.com', phone: '13800000001', address: '北京市朝阳区' },
{ id: 2, name: '李四', age: 28, department: '产品部', role: '产品经理', email: 'lisi@example.com', phone: '13800000002', address: '上海市浦东新区' },
]
</script>
<template>
<ProTable :columns="columns" :data="data" :scroll-x="1260" :pagination="false" />
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
选择列与序号列
特殊列配置
批量操作的选择列和序号列都可在列设置中显示、隐藏、排序或固定;序号可切换是否跨页连续。
vue
<script setup lang="ts">
import type { ProTableBatchAction, ProTableColumn } from '@naive-ui-pro/pro-table'
import { ProTable } from '@naive-ui-pro/pro-table'
import { NSpace, NSwitch, NText } from 'naive-ui'
import { ref } from 'vue'
const showIndex = ref(true)
const continuousIndex = ref(true)
const actionMessage = ref('')
const columns: ProTableColumn[] = [
{ title: '姓名', key: 'name' },
{ title: '部门', key: 'department' },
{ title: '职位', key: 'role' },
]
const departments = ['研发部', '产品部', '设计部']
const roles = ['前端工程师', '产品经理', 'UI 设计师']
const data = Array.from({ length: 13 }, (_, index) => ({
id: index + 1,
name: `用户 ${index + 1}`,
department: departments[index % departments.length],
role: roles[index % roles.length],
}))
const batchActions: ProTableBatchAction[] = [{
key: 'archive',
label: '批量归档',
onClick(keys) {
actionMessage.value = `已归档 ${keys.length} 项`
},
}]
</script>
<template>
<NSpace align="center" style="margin-bottom: 16px">
<NText>显示序号</NText>
<NSwitch v-model:value="showIndex" />
<NText>跨页连续</NText>
<NSwitch v-model:value="continuousIndex" :disabled="!showIndex" />
<NText v-if="actionMessage" depth="3">
{{ actionMessage }}
</NText>
</NSpace>
<ProTable
:batch-actions="batchActions"
:columns="columns"
:continuous-index="continuousIndex"
:data="data"
:pagination="{ pageSize: 5 }"
:show-index="showIndex"
:option="{ search: false }"
/>
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
工具栏配置
工具栏配置
刷新、全屏、密度和列设置操作。
vue
<script setup lang="ts">
import type { ProTableColumn } from '@naive-ui-pro/pro-table'
import { ProTable } from '@naive-ui-pro/pro-table'
import { NCheckbox, NSpace } from 'naive-ui'
import { reactive } from 'vue'
const columns: ProTableColumn[] = [
{ title: '姓名', key: 'name' },
{ title: '部门', key: 'department' },
{ title: '角色', key: 'role' },
]
const data = [{ id: 1, name: '张三', department: '研发部', role: '前端工程师' }]
const option = reactive({
tableHeader: true,
full: true,
reload: true,
setting: true,
size: true,
})
</script>
<template>
<NSpace style="margin-bottom: 16px;" wrap>
<NCheckbox v-model:checked="option.tableHeader">
TableHeader
</NCheckbox>
<NCheckbox v-model:checked="option.reload">
刷新
</NCheckbox>
<NCheckbox v-model:checked="option.full">
全屏
</NCheckbox>
<NCheckbox v-model:checked="option.size">
密度
</NCheckbox>
<NCheckbox v-model:checked="option.setting">
列设置
</NCheckbox>
</NSpace>
<ProTable :columns="columns" :data="data" :pagination="false" :option="option">
<template #title>
<strong>用户列表</strong>
</template>
</ProTable>
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
自定义插槽
自定义插槽
自定义标题和工具栏右侧内容。
vue
<script setup lang="ts">
import type { ProTableColumn } from '@naive-ui-pro/pro-table'
import { ProTable } from '@naive-ui-pro/pro-table'
import { NButton } from 'naive-ui'
const columns: ProTableColumn[] = [
{ title: '姓名', key: 'name' },
{ title: '部门', key: 'department' },
{ title: '角色', key: 'role' },
]
const data = [{ id: 1, name: '张三', department: '研发部', role: '前端工程师' }]
</script>
<template>
<ProTable :columns="columns" :data="data" :pagination="false">
<template #title>
<strong>自定义标题</strong>
</template>
<template #header-extra>
<NButton type="primary" size="small">
新增用户
</NButton>
</template>
</ProTable>
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
在表头操作选中行
title、header 和 header-extra 插槽可通过 keys、rows 获取当前选中项,直接执行批量操作。
vue
<script setup lang="ts">
import type { ProTableColumn, ProTableRecord } from '@naive-ui-pro/pro-table'
import { ProTable } from '@naive-ui-pro/pro-table'
import { NButton, NButtonGroup, NSpace, NTag, NText, useMessage } from 'naive-ui'
import { ref } from 'vue'
const message = useMessage()
const checkedKeys = ref<(string | number)[]>([])
const data = ref([
{ id: 1, name: '张三', department: '研发部', status: '启用' },
{ id: 2, name: '李四', department: '产品部', status: '停用' },
{ id: 3, name: '王五', department: '设计部', status: '启用' },
{ id: 4, name: '赵六', department: '运营部', status: '停用' },
])
const columns: ProTableColumn[] = [
{ type: 'selection' },
{ title: '姓名', key: 'name' },
{ title: '部门', key: 'department' },
{ title: '状态', key: 'status' },
]
function updateStatus(rows: ProTableRecord[], status: string): void {
const selectedIds = new Set(rows.map(row => row.id))
data.value = data.value.map(row =>
selectedIds.has(row.id) ? { ...row, status } : row,
)
message.success(`已将 ${rows.length} 位成员设为${status}`)
checkedKeys.value = []
}
</script>
<template>
<ProTable
v-model:checked-row-keys="checkedKeys"
:columns="columns"
:data="data"
:pagination="false"
:show-index="false"
:option="{ search: false }"
>
<template #title="{ keys }">
<NSpace align="center">
<NText strong>
团队成员
</NText>
<NTag v-if="keys.length" size="small" type="info" round>
已选 {{ keys.length }} 人
</NTag>
</NSpace>
</template>
<template #header-extra="{ keys, rows }">
<NButtonGroup size="small">
<NButton :disabled="!keys.length" @click="updateStatus(rows, '启用')">
启用
</NButton>
<NButton :disabled="!keys.length" @click="updateStatus(rows, '停用')">
停用
</NButton>
</NButtonGroup>
</template>
</ProTable>
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
实例方法
调用 ProTable / NDataTable 方法
覆盖 ProTableInst 的全部增强方法、DataTableInst 方法和只读状态。
vue
<script setup lang="ts">
import type {
ProTableColumn,
ProTableInst,
ProTableRequestResult,
} from '@naive-ui-pro/pro-table'
import { ProTable } from '@naive-ui-pro/pro-table'
import { NAlert, NButton, NCode, NSpace, NText } from 'naive-ui'
import { nextTick, ref } from 'vue'
interface MethodAction {
label: string
run: (table: ProTableInst) => unknown
}
const tableRef = ref<ProTableInst | null>(null)
const result = ref('点击按钮调用 ProTable 或 NDataTable 实例方法')
const snapshot = ref('{}')
const columns: ProTableColumn[] = [
{ title: '姓名', key: 'name' },
{ title: '年龄', key: 'age', sorter: true },
{
title: '部门',
key: 'department',
filterOptions: [
{ label: '研发部', value: '研发部' },
{ label: '产品部', value: '产品部' },
],
},
]
const sourceData = [
{ id: 1, name: '张三', age: 32, department: '研发部' },
{ id: 2, name: '李四', age: 24, department: '产品部' },
{ id: 3, name: '王五', age: 29, department: '研发部' },
{ id: 4, name: '赵六', age: 35, department: '产品部' },
]
async function request(params: Record<string, unknown>): Promise<ProTableRequestResult> {
const keyword = String(params.name ?? '')
const filteredData = sourceData.filter(row => row.name.includes(keyword))
const page = Number(params.current ?? 1)
const pageSize = Number(params.size ?? 2)
const start = (page - 1) * pageSize
await Promise.resolve()
return { data: filteredData.slice(start, start + pageSize), total: filteredData.length }
}
const proTableActions: MethodAction[] = [
{ label: 'reload()', run: table => table.reload() },
{ label: 'request()', run: table => table.request({ name: '李' }) },
{ label: 'search()', run: table => table.search({ name: '张' }) },
{ label: 'reset()', run: table => table.reset() },
{ label: 'setParams()', run: table => table.setParams({ name: '王' }) },
{ label: 'updateParams()', run: table => table.updateParams({ source: 'demo' }) },
]
const dataTableActions: MethodAction[] = [
{ label: 'filter()', run: table => table.filter({ department: ['研发部'] }) },
{ label: 'filters()', run: table => table.filters({ department: ['产品部'] }) },
{ label: 'clearFilters()', run: table => table.clearFilters() },
{ label: 'clearFilter()', run: table => table.clearFilter() },
{ label: 'sort()', run: table => table.sort('age', 'ascend') },
{ label: 'clearSorter()', run: table => table.clearSorter() },
{ label: 'page()', run: table => table.page(2) },
{ label: 'scrollTo()', run: table => table.scrollTo({ top: 0, behavior: 'smooth' }) },
{ label: 'downloadCsv()', run: table => table.downloadCsv() },
]
async function invoke(action: MethodAction): Promise<void> {
const table = tableRef.value
if (!table)
return
await action.run(table)
await nextTick()
result.value = `已调用 ${action.label}`
snapshot.value = JSON.stringify({
data: table.data,
index: table.index,
params: table.params,
}, null, 2)
}
</script>
<template>
<NSpace vertical :size="12">
<NText strong>
ProTable 方法
</NText>
<NSpace>
<NButton
v-for="action in proTableActions"
:key="action.label"
type="primary"
secondary
@click="invoke(action)"
>
{{ action.label }}
</NButton>
</NSpace>
<NText strong>
NDataTable 方法
</NText>
<NSpace>
<NButton
v-for="action in dataTableActions"
:key="action.label"
@click="invoke(action)"
>
{{ action.label }}
</NButton>
</NSpace>
<NAlert type="info" :show-icon="false">
{{ result }}
</NAlert>
<NCode :code="snapshot" language="json" word-wrap />
<ProTable
ref="tableRef"
:columns="columns"
:request="request"
:option="false"
:pagination="{ pageSize: 2 }"
/>
</NSpace>
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
API
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| columns | ProTableColumn[] | [] | 列配置 |
| data | ProTableRecord[] | [] | 静态数据 |
| title | string | - | 工具栏标题;title 插槽优先级更高 |
| request | (params) => Promise<{data, total}> | - | 远程请求函数 |
| defaultParams | Record<string, unknown> | {} | 默认查询参数 |
| manual | boolean | false | 手动触发首次请求 |
| option | false | ProTableOption | - | 搜索区与 TableHeader 配置 |
| pagination | false | PaginationProps | {} | 分页配置 |
| batchActions | ProTableBatchAction[] | [] | 批量操作配置 |
| checkedRowKeys | (string|number)[] | - | 选中行 keys(v-model) |
| showIndex | boolean | true | 是否显示序号列,序号列可在列设置中配置 |
| continuousIndex | boolean | true | 序号是否跨页连续 |
| searchDebounce | number | 300 | 搜索防抖(ms) |
继承 Naive UI NDataTable 全部 Props。
ProTableOption
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| tableHeader | boolean | true | 是否显示 TableHeader;同时控制自定义 header 插槽 |
| search | boolean | true | 是否显示搜索区域 |
| reload | boolean | true | 是否显示刷新按钮 |
| full | boolean | true | 是否显示全屏按钮 |
| size | boolean | true | 是否显示密度按钮 |
| setting | boolean | true | 是否显示列设置按钮 |
| manualSearch | boolean | false | 搜索项变化时是否仅手动触发查询 |
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
| reset | - | 重置搜索时触发 |
| search | params | 搜索时触发 |
| update:checkedRowKeys | (string|number)[] | 选中行变化 |
Slots
| 插槽名 | 参数 | 说明 |
|---|---|---|
| default | props | 自定义表格内容 |
| title | { keys, rows } | 工具栏标题,可获取选中行 |
| header | { keys, rows } | 自定义整个工具栏,可获取选中行 |
| header-extra | { keys, rows } | 工具栏右侧额外内容,可获取选中行 |
| form | ProTableFormSlotProps | 自定义搜索字段 |
| batch-actions | { keys, rows } | 自定义批量操作栏 |
Methods
除 reload、request、reset、search、setParams、updateParams 外,完整继承 Naive UI DataTableInst:
filter、filters、clearFilters、clearSorter、page、sort、scrollTo、downloadCsv、clearFilter。