ProTable 增强表格
ProTable 是一个增强版的表格组件,集成了搜索、分页、列设置等功能,适用于中后台管理系统。
基础用法
最基础的表格展示用法。
vue
<template>
<NProTable :columns="columns" :data="data" />
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const data = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
</script>请求数据
通过 requestApi 属性传入请求函数,自动获取数据。
vue
<template>
<NProTable :columns="columns" :requestApi="getData" />
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const getData = async (params) => {
// 模拟 API 请求
const { pageNum = 1, pageSize = 10 } = params
const list = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
return {
data: {
list: list.slice((pageNum - 1) * pageSize, pageNum * pageSize),
total: list.length,
},
}
}
</script>搜索表单
在列配置中设置 search 属性来启用搜索功能。
vue
<template>
<NProTable :columns="columns" :requestApi="getData" />
</template>
<script setup>
const columns = [
{
prop: 'name',
label: '姓名',
search: {
el: 'input',
label: '姓名',
order: 1,
},
},
{
prop: 'status',
label: '状态',
search: {
el: 'select',
label: '状态',
order: 2,
},
enum: [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 },
],
},
{
prop: 'createTime',
label: '创建时间',
search: {
el: 'date-picker',
label: '创建时间',
order: 3,
},
},
{ prop: 'address', label: '地址' },
]
const getData = async (params) => {
// 模拟 API 请求
return {
data: {
list: [],
total: 0,
},
}
}
</script>多选
设置 type="selection" 来启用多选功能。
vue
<template>
<NProTable
ref="proTableRef"
:columns="columns"
:data="data"
>
<template #tableHeader="{ selectedList, isSelected }">
<NButton :disabled="!isSelected" type="primary">
删除 ({{ selectedList.length }})
</NButton>
</template>
</NProTable>
</template>
<script setup>
import { ref } from 'vue'
const proTableRef = ref(null)
const columns = [
{ type: 'selection' },
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const data = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
</script>索引列
设置 type="index" 来显示索引列。
vue
<template>
<NProTable :columns="columns" :data="data" />
</template>
<script setup>
const columns = [
{ type: 'index' },
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const data = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
</script>操作列
使用 render 属性来自定义操作列。
vue
<template>
<NProTable :columns="columns" :data="data" />
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
{
label: '操作',
prop: 'operation',
render: (scope) => (
<div>
<el-button type="primary" link>
编辑
</el-button>
<el-button type="danger" link>
删除
</el-button>
</div>
),
},
]
const data = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
</script>列设置
设置 toolButton 属性来启用列设置功能。
vue
<template>
<NProTable
:columns="columns"
:data="data"
:toolButton="['refresh', 'setting', 'search']"
/>
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const data = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
</script>自定义表头
使用 headerRender 属性来自定义表头。
vue
<template>
<NProTable :columns="columns" :data="data" />
</template>
<script setup>
const columns = [
{
prop: 'name',
label: '姓名',
headerRender: (scope, column) => (
<div>
<span>{column.label}</span>
<el-tooltip content="这是姓名列">
<el-icon style="margin-left: 4px;"><QuestionFilled /></el-icon>
</el-tooltip>
</div>
),
},
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const data = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
</script>隐藏列
设置 isShow 属性为 false 来隐藏列。
vue
<template>
<NProTable :columns="columns" :data="data" />
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址', isShow: false },
]
const data = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
</script>禁用列设置
设置 isSetting 属性为 false 来禁止列设置。
vue
<template>
<NProTable :columns="columns" :data="data" />
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名', isSetting: false },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const data = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
</script>标签列
设置 tag 属性为 true 来显示标签样式。
vue
<template>
<NProTable :columns="columns" :data="data" />
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名' },
{
prop: 'status',
label: '状态',
tag: true,
enum: [
{ label: '启用', value: 1, tagType: 'success' },
{ label: '禁用', value: 0, tagType: 'danger' },
],
},
{ prop: 'address', label: '地址' },
]
const data = [
{ id: 1, name: '张三', status: 1, address: '北京市' },
{ id: 2, name: '李四', status: 0, address: '上海市' },
{ id: 3, name: '王五', status: 1, address: '广州市' },
]
</script>展开行
设置 type="expand" 和使用 expand 插槽来实现展开行。
vue
<template>
<NProTable :columns="columns" :data="data">
<template #expand="{ row }">
<div style="padding: 16px;">
<p>姓名: {{ row.name }}</p>
<p>年龄: {{ row.age }}</p>
<p>地址: {{ row.address }}</p>
</div>
</template>
</NProTable>
</template>
<script setup>
const columns = [
{ type: 'expand' },
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const data = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
</script>拖拽排序
设置 type="sort" 来启用拖拽排序。
vue
<template>
<NProTable :columns="columns" :data="data" @dragSort="handleDragSort" />
</template>
<script setup>
const columns = [
{ type: 'sort' },
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const data = ref([
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
])
const handleDragSort = ({ newIndex, oldIndex }) => {
console.log('拖拽排序:', newIndex, oldIndex)
}
</script>禁用分页
设置 pagination 为 false 来禁用分页。
vue
<template>
<NProTable :columns="columns" :data="data" :pagination="false" />
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const data = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
</script>自定义分页大小
使用 pageSizes 属性来自定义分页大小选项。
vue
<template>
<NProTable :columns="columns" :data="data" :pageSizes="[5, 10, 20, 50]" />
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const data = [
{ id: 1, name: '张三', age: 20, address: '北京市' },
{ id: 2, name: '李四', age: 25, address: '上海市' },
{ id: 3, name: '王五', age: 30, address: '广州市' },
]
</script>初始请求参数
使用 initParam 属性来设置初始请求参数。
vue
<template>
<NProTable :columns="columns" :requestApi="getData" :initParam="initParam" />
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const initParam = {
status: 1,
type: 'all',
}
const getData = async (params) => {
console.log('请求参数:', params)
return {
data: {
list: [],
total: 0,
},
}
}
</script>数据回调
使用 dataCallback 属性来处理请求返回的数据。
vue
<template>
<NProTable :columns="columns" :requestApi="getData" :dataCallback="dataCallback" />
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const getData = async (params) => {
return {
code: 200,
data: {
records: [],
total: 0,
},
}
}
const dataCallback = (data) => {
return {
list: data.records,
total: data.total,
}
}
</script>请求错误处理
使用 requestError 属性来处理请求错误。
vue
<template>
<NProTable :columns="columns" :requestApi="getData" :requestError="requestError" />
</template>
<script setup>
const columns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const getData = async (params) => {
throw new Error('请求失败')
}
const requestError = (error) => {
console.error('请求错误:', error)
}
</script>禁用自动请求
设置 requestAuto 为 false 来禁用自动请求。
vue
<template>
<NProTable
ref="proTableRef"
:columns="columns"
:requestApi="getData"
:requestAuto="false"
/>
<NButton @click="handleSearch">手动请求</NButton>
</template>
<script setup>
import { ref } from 'vue')
const proTableRef = ref(null)
const columns = [
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' },
{ prop: 'address', label: '地址' },
]
const getData = async (params) => {
return {
data: {
list: [],
total: 0,
},
}
}
const handleSearch = () => {
proTableRef.value.getTableList()
}
</script>API
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| columns | 列配置 | ColumnProps[] | [] |
| data | 静态数据 | any[] | — |
| requestApi | 获取数据的 API | (params: any) => Promise<any> | — |
| requestAuto | 是否自动执行请求 | boolean | true |
| requestError | 请求错误回调 | (params: any) => void | — |
| dataCallback | 数据回调,可以处理数据 | (data: any) => any | — |
| title | 表格标题 | string | — |
| pagination | 是否显示分页 | boolean | true |
| initParam | 初始化请求参数 | any | {} |
| border | 是否显示边框 | boolean | true |
| toolButton | 工具栏按钮 | ('refresh' | 'setting' | 'search')[] | boolean | true |
| rowKey | 行数据的 Key | string | 'id' |
| pageSizes | 分页大小选项 | number[] | [10, 25, 50, 100] |
ColumnProps
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| type | 列类型 | 'index' | 'selection' | 'radio' | 'expand' | 'sort' | — |
| prop | 字段名称 | string | — |
| label | 列标题 | string | — |
| width | 列宽度 | string | number | — |
| minWidth | 列最小宽度 | string | number | — |
| fixed | 列是否固定 | boolean | 'left' | 'right' | false |
| sortable | 对应列是否可以排序 | boolean | 'custom' | false |
| align | 对齐方式 | 'left' | 'center' | 'right' | 'left' |
| headerAlign | 表头对齐方式 | 'left' | 'center' | 'right' | — |
| showOverflowTooltip | 当内容过长被隐藏时显示 tooltip | boolean | false |
| tag | 是否显示标签样式 | boolean | Ref<boolean> | false |
| isShow | 是否显示列 | boolean | Ref<boolean> | true |
| isSetting | 是否允许列设置 | boolean | Ref<boolean> | true |
| search | 搜索配置 | SearchProps | — |
| enum | 枚举数据 | EnumProps[] | Ref<EnumProps[]> | ((params?: any) => Promise<any>) | — |
| isFilterEnum | 是否过滤枚举 | boolean | Ref<boolean> | true |
| fieldNames | 字段名映射 | FieldNamesProps | — |
| headerRender | 自定义表头渲染 | (scope: HeaderRenderScope, column?: any) => VNode | — |
| render | 自定义渲染 | (scope: RenderScope) => VNode | string | — |
| _children | 子列配置 | ColumnProps[] | — |
| tooltip | 提示信息 | string | — |
SearchProps
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| el | 搜索组件类型 | 'input' | 'input-number' | 'select' | 'select-v2' | 'tree-select' | 'cascader' | 'date-picker' | 'time-picker' | 'time-select' | 'switch' | 'slider' | 'input' |
| label | 搜索标签 | string | — |
| props | 组件属性 | any | — |
| key | 搜索参数键名 | string | — |
| tooltip | 提示信息 | string | — |
| order | 排序 | number | 0 |
| span | 栅栏占据的列数 | number | 6 |
| offset | 栅栏左侧偏移格数 | number | 0 |
| defaultValue | 默认值 | string | number | boolean | any[] | Ref<any> | — |
| render | 自定义渲染 | (scope: SearchRenderScope) => VNode | — |
Events
| 事件名 | 说明 | 类型 |
|---|---|---|
| search | 点击搜索按钮时触发 | () => void |
| reset | 点击重置按钮时触发 | () => void |
| dragSort | 拖拽排序时触发 | (args: { newIndex?: number; oldIndex?: number }) => void |
Slots
| 插槽名 | 说明 | 作用域 |
|---|---|---|
| tableHeader | 表格头部左侧内容 | { selectedList, selectedListIds, isSelected } |
| toolButton | 工具栏按钮 | — |
| expand | 展开行内容 | { row, $index } |
| empty | 空数据时的内容 | — |
方法
| 方法名 | 说明 | 类型 |
|---|---|---|
| getTableList | 获取表格数据 | () => void |
| search | 执行搜索 | () => void |
| reset | 重置搜索 | () => void |
| handleSizeChange | 改变分页大小 | (size: number) => void |
| handleCurrentChange | 改变当前页 | (page: number) => void |
| clearSelection | 清空选择 | () => void |
| toggleSearchVisibility | 切换搜索栏显示 | (value: boolean) => void |
属性
| 属性名 | 说明 | 类型 |
|---|---|---|
| element | 表格实例 | Ref<ElTable> |
| tableData | 表格数据 | Ref<any[]> |
| radio | 单选值 | Ref<string> |
| pageable | 分页信息 | Ref<Pageable> |
| searchParam | 搜索参数 | Ref<{ [key: string]: any }> |
| searchInitParam | 搜索初始参数 | Ref<{ [key: string]: any }> |
| isSelected | 是否选中 | Ref<boolean> |
| selectedList | 选中列表 | Ref<any[]> |
| selectedListIds | 选中列表 ID | Ref<any[]> |
| isShowSearch | 是否显示搜索栏 | Ref<boolean> |
| enumMap | 枚举映射 | Ref<Map<string, EnumProps[]>> |