@hz_yujin/vue2-base-table
v0.3.30
Published
Vue 2 ProTable / ProPageTable:搜索、valueType、筛选、持久化、树表、行内编辑、批量操作、骨架屏、导出打印、移动端卡片、ProDialog(兼容 Vue 2.6 + @vue/composition-api / Vue 2.7)
Maintainers
Readme
@hz_yujin/vue2-base-table
基于 Vue 2.6 / 2.7 + Element UI + vxe-table 的 ProTable 组件库。
- Vue 2.7:直接使用内置 Composition API
- Vue 2.6:需安装并注册
@vue/composition-api(老项目如已安装可直接复用)
能力概览
| 能力 | 说明 |
|------|------|
| ProPageTable / ProTable / ProSearchForm | 搜索 + 表格一体化 |
| ProDialog | 独立弹框封装(与表格并列组合,非表格内置) |
| valueType | money / digit / percent / date / datetime / tag / select / link / image / copyable |
| 表头筛选 | 列 filters + 持久化 |
| 搜索控件 | input / textarea / number / select / select-multiple / date* / radio / checkbox / switch / slot |
| useProTableRequest | Composition API 受控请求封装 |
| 工具栏 | 刷新 / 全屏 / 列设置(默认);导出 / 打印需 toolbar.export / print 开启;toolbar.zoom: false 可关全屏 |
| 树表 | tree-config |
| 行内编辑 | edit-config + 列 editRender |
| 批量操作 | batch-actions |
| 跨页多选 | reserve-selection(需配合 row-key) |
| 序号 | show-seq 默认开启;有分页时跨页连续 |
| 骨架屏 | skeleton |
| 持久化 | storage-key(分页/排序/筛选/搜索/展开/列) |
| 移动端卡片 | mobile-card |
安装
Vue 2.7
npm install @hz_yujin/vue2-base-table element-ui [email protected] xe-utilsVue 2.6(如 2.6.14)
npm install @hz_yujin/vue2-base-table element-ui [email protected] xe-utils @vue/composition-api老项目若已有
@vue/composition-api,无需重复安装。
注册
Vue 2.7
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import VXETable from 'vxe-table'
import 'vxe-table/lib/style.css'
import Vue2BaseTable from '@hz_yujin/vue2-base-table'
import '@hz_yujin/vue2-base-table/style.css'
Vue.use(ElementUI)
Vue.use(VXETable)
// 宿主布局层级较高时可:Vue.use(Vue2BaseTable, { zIndex: 4000 })
Vue.use(Vue2BaseTable)Vue 2.6
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import VXETable from 'vxe-table'
import 'vxe-table/lib/style.css'
import Vue2BaseTable from '@hz_yujin/vue2-base-table'
import '@hz_yujin/vue2-base-table/style.css'
// 必须在表格插件之前注册
Vue.use(VueCompositionAPI)
Vue.use(ElementUI)
Vue.use(VXETable)
Vue.use(Vue2BaseTable)Vue CLI 3 工程如遇 ESM 解析问题,可在
vue.config.js中加入:transpileDependencies: ['@hz_yujin/vue2-base-table', 'vue-demi']
全局注册组件名:ProTable、ProSearchForm、ProPageTable、ProDialog。支持 prefix、zIndex,例如 Vue.use(Vue2BaseTable, { prefix: 'Hz', zIndex: 4000 })。
ProPageTable(推荐入口)
搜索区 + ProTable 的页面级组合。业务侧通常配合 useProTableRequest 做远程分页 / 排序 / 筛选。
快速开始
<template>
<ProPageTable
:search-fields="searchFields"
:search-model.sync="searchModel"
:columns="columns"
:data="data"
:loading="loading"
:pagination="pagination"
storage-key="user-list"
selection
@search="handleSearch"
@reset="handleReset"
@page-change="handlePageChange"
@sort-change="handleSortChange"
@filter-change="handleFilterChange"
@refresh="loadData"
>
<template #action="{ row }">
<el-button type="text" size="mini" @click="onEdit(row)">编辑</el-button>
</template>
</ProPageTable>
</template>
<script>
import { useProTableRequest } from '@hz_yujin/vue2-base-table'
export default {
setup() {
const columns = [
{ field: 'name', title: '姓名', minWidth: 120, sortable: true, search: true },
{
field: 'status',
title: '状态',
width: 100,
valueType: 'tag',
valueEnum: {
启用: { text: '启用', status: 'success' },
禁用: { text: '禁用', status: 'info' },
},
filters: [
{ label: '启用', value: '启用' },
{ label: '禁用', value: '禁用' },
],
search: { type: 'select' },
},
{ field: 'createdAt', title: '创建时间', minWidth: 160, valueType: 'datetime' },
{ field: 'action', title: '操作', width: 100, fixed: 'right', slot: 'action' },
]
const {
searchFields,
searchModel,
data,
loading,
pagination,
loadData,
handleSearch,
handleReset,
handlePageChange,
handleSortChange,
handleFilterChange,
} = useProTableRequest({
columns,
storageKey: 'user-list',
fetcher: async ({ currentPage, pageSize, form, sort, filters, signal }) => {
// 返回 { list, total };可用 signal 取消过期请求
const res = await api.fetchUsers({ currentPage, pageSize, form, sort, filters, signal })
return { list: res.list, total: res.total }
},
})
function onEdit(row) {
// ...
}
return {
columns,
searchFields,
searchModel,
data,
loading,
pagination,
loadData,
handleSearch,
handleReset,
handlePageChange,
handleSortChange,
handleFilterChange,
onEdit,
}
},
}
</script>排序 / 筛选均为 remote:点击表头后会触发
sort-change/filter-change,需业务重新请求数据(useProTableRequest已内置处理)。
Props(搜索区)
| Prop | 类型 | 默认 | 说明 |
|------|------|------|------|
| showSearch | Boolean | true | 是否显示搜索区(仍需 searchFields 有字段才会渲染) |
| searchFields | Array | [] | 搜索字段配置,见下方「搜索字段」 |
| searchModel | Object | {} | 搜索表单值,配合 .sync / update:searchModel |
| searchTitle | String | '' | 搜索区标题 |
| searchText | String | '查询' | 查询按钮文案 |
| resetText | String | '重置' | 重置按钮文案 |
| searchCollapsible | Boolean | true | 字段过多时是否可折叠 |
| searchDefaultExpanded | Boolean | false | 默认是否展开全部字段 |
| searchCollapseVisibleCount | Number | 3 | 收起时可见字段数 |
| searchPanelDefaultVisible | Boolean | true | 查询条件模块默认是否展开;可用工具栏漏斗按钮切换 |
Props(表格区,透传 ProTable)
| Prop | 类型 | 默认 | 说明 |
|------|------|------|------|
| data | Array | [] | 表格数据 |
| columns | Array | [] | 列配置,见下方「列配置」 |
| loading | Boolean | false | 加载中 |
| emptyText | String | '暂无数据' | 空状态文案 |
| border | Boolean | true | 边框 |
| stripe | Boolean | true | 斑马纹 |
| height | String \| Number | — | 表格高度 |
| minHeight | String \| Number | — | 表格最小高度 |
| rowKey | String \| Function | 'id' | 行唯一键;跨页多选时需为字符串字段名 |
| selection | Boolean \| String | false | false / true / 'checkbox' / 'radio' |
| reserveSelection | Boolean | false | 跨页保留勾选(需配合 rowKey) |
| showSeq | Boolean | true | 序号列;有分页时跨页连续 |
| toolbar | Boolean \| Object | true | 工具栏配置,见下方 |
| pagination | Boolean \| Object | { currentPage: 1, pageSize: 20, total: 0 } | 分页;false 关闭 |
| storageKey | String | — | 持久化键;传入后默认开启相关持久化 |
| persist | Boolean \| Object | — | 精细控制持久化项,见下方 |
| treeConfig | Boolean \| Object | false | 树表配置,默认 children: 'children' |
| editConfig | Object | — | 行内编辑(透传 vxe edit-config) |
| batchActions | Boolean \| Object | false | 批量操作条;有选中行时显示 |
| skeleton | Boolean \| Object | true | 骨架屏 |
| mobileCard | Boolean \| Object | true | 窄屏卡片列表 |
| headerBgColor | String | — | 受控表头背景色 |
Events
| 事件 | 说明 |
|------|------|
| update:searchModel / update:search-model | 搜索模型变更 |
| search | 点击查询,参数为当前搜索模型 |
| reset | 点击重置,参数为重置后的搜索模型 |
| search-panel-visible-change | 查询条件模块展开/收起 |
| page-change | { currentPage, pageSize } |
| sort-change | { field, order },order 为 'asc' / 'desc' / null |
| filter-change | { filters, field },filters 为 { field, values }[] |
| selection-change | { records, reserves } |
| refresh | 工具栏刷新 |
| persist-ready | 持久化状态恢复完成,参数为已恢复状态 |
| edit-save | 行内编辑关闭后 { row, field, value, oldValue } |
| header-bg-color-change / update:headerBgColor | 表头背景色变更 |
Slots
| 插槽 | 说明 |
|------|------|
| 列字段同名 / slot 指定名 | 自定义单元格,作用域含 row 等 |
| toolbar-left / toolbar-right | 工具栏左右扩展 |
| batch-actions | 批量操作区,作用域 { selected, clear } |
| search-* / 搜索字段 key | 自定义搜索控件(字段 type: 'slot') |
| empty / skeleton | 空状态 / 骨架屏(透传 ProTable) |
ProTable
纯表格(无搜索区)。Props / Events / Slots 与上表「表格区」一致;pagination 默认 false。
额外事件:row-click、zoom、custom、edit-closed、edit-activated。
实例方法
| 方法 | 说明 |
|------|------|
| getCheckboxRecords(includeReserve?) | 获取勾选行;默认跟随 reserveSelection |
| clearSelection() | 清空勾选 / 单选 |
| clearPersist() | 清除当前 storageKey 的持久化状态 |
| getGridRef() | 获取内部 vxe-grid 实例 |
this.$refs.table.getCheckboxRecords()
this.$refs.table.clearSelection()列配置 columns
| 字段 | 说明 |
|------|------|
| field / prop / key | 数据字段(三者任选,优先级 field > prop > key) |
| title / label | 列标题 |
| width / minWidth | 列宽;未设 minWidth 时默认 100 |
| fixed | 'left' / 'right' |
| align / headerAlign | 对齐,默认居中 |
| visible | false 时隐藏 |
| children | 分组表头 |
| sortable | 是否可排序(remote) |
| filters | 表头筛选项 [{ label, value }](remote) |
| filterMultiple | 是否多选筛选,默认 true |
| resizable | 是否可拖拽改宽 |
| showOverflow | 溢出省略,默认 true |
| treeNode | 树节点列 |
| editRender | 行内编辑渲染,如 { name: 'input' } |
| type | 'seq' / 'checkbox' / 'radio' / 'expand' |
| valueType | 内置单元格类型,见下表 |
| valueEnum | 枚举映射:{ [value]: string \| { text, status } } |
| formatter | (params) => string,优先于 valueType 文本格式化 |
| render | 自定义渲染函数(走内置单元格) |
| slot | 自定义插槽名;默认等于字段名 |
| fieldProps | 传给内置单元格的附加属性(如 image 宽高、link target) |
| search | true | false | 对象,见「从列生成搜索字段」 |
| cardAction | 标记为操作列(移动端卡片中按操作区处理) |
操作列约定:field / slot 为 action,或标题为「操作」,或 cardAction: true 时,自动关闭排序与拖拽改宽。
valueType
| 类型 | 说明 |
|------|------|
| digit | 整数本地化显示 |
| money | 两位小数 |
| percent | 按 0–1 小数转为百分比(如 0.85 → 85.00%) |
| date / datetime | 日期 / 日期时间 |
| tag | 配合 valueEnum.status 显示标签色 |
| select | 配合 valueEnum 显示文案 |
| link | 链接;fieldProps 可传 target 等 |
| image | 图片;fieldProps 可传 width / height |
| copyable | 可复制文本 |
自定义:
import { registerValueType } from '@hz_yujin/vue2-base-table'
registerValueType('score', {
format: (v) => (v == null || v === '' ? '—' : `${Number(v).toFixed(1)} 分`),
})列示例
const columns = [
{ type: 'expand', width: 48, slot: 'expand' },
{ field: 'name', title: '姓名', minWidth: 120, sortable: true, search: true },
{
field: 'dept',
title: '部门',
minWidth: 100,
filters: [
{ label: '研发', value: '研发' },
{ label: '产品', value: '产品' },
],
},
{
field: 'status',
title: '状态',
width: 90,
valueType: 'tag',
valueEnum: {
启用: { text: '启用', status: 'success' },
禁用: { text: '禁用', status: 'info' },
},
},
{ field: 'amount', title: '金额', width: 110, align: 'right', valueType: 'money' },
{ field: 'createdAt', title: '创建时间', minWidth: 160, valueType: 'datetime' },
{ field: 'action', title: '操作', width: 140, fixed: 'right', slot: 'action' },
]搜索字段
用于 ProPageTable 的 searchFields / ProSearchForm 的 fields。
| 字段 | 说明 |
|------|------|
| key | 表单字段名(必填) |
| label | 标签 |
| type | 控件类型,默认 input |
| placeholder | 占位符 |
| width | 控件宽度(px) |
| options | select / radio / checkbox-group 选项 [{ label, value }] |
| defaultValue | 默认值;未设时按类型推断 |
| props | 透传给底层 Element 控件 |
控件类型
| type | 说明 |
|------|------|
| input | 输入框(默认) |
| textarea | 多行文本 |
| number | 数字 |
| select / select-multiple | 单选 / 多选下拉 |
| date / datetime | 日期 / 日期时间 |
| daterange / datetimerange | 日期 / 日期时间范围 |
| radio / radio-button | 单选 |
| checkbox | 单个勾选(布尔) |
| checkbox-group | 多选组 |
| switch | 开关 |
| slot | 自定义插槽(插槽名 = key,或 search-${key}) |
从列生成搜索字段
列上配置 search 后,useProTableRequest / buildSearchFieldsFromColumns 会自动生成搜索项:
search: true→ 有filters则为select,否则inputsearch: { key?, label?, type?, placeholder?, width?, options?, defaultValue?, props? }→ 覆盖默认
显式传入的 searchFields 会与列生成结果按 key 合并(显式优先)。
useProTableRequest
Composition API 受控请求封装。
选项
| 选项 | 说明 |
|------|------|
| fetcher | 必填。(params) => Promise<{ list, total }> |
| columns | 用于从列推导搜索字段 |
| searchFields | 显式搜索字段(与列推导合并) |
| searchModel | 初始搜索模型 |
| defaultPageSize | 默认页大小,默认 20 |
| storageKey / persist | 与表格持久化对齐,用于恢复 pageSize / sort / filters / search |
| immediate | 是否在 onMounted 立即请求,默认 true |
fetcher 参数:
{
currentPage: number
pageSize: number
form: Record<string, unknown> // 搜索模型快照
sort: { field: string | null, order: 'asc' | 'desc' | null }
filters: Record<string, Array<string | number | boolean>> // field -> values
signal: AbortSignal // 新请求会 abort 上一次
}返回值
| 字段 | 说明 |
|------|------|
| searchFields / searchModel | 合并后的字段与响应式模型 |
| data / loading / pagination | 表格绑定数据 |
| sortState / columnFilters | 当前排序与筛选 |
| loadData / refresh | 重新请求 |
| handleSearch / handleReset | 查询 / 重置(会重置到第 1 页) |
| handlePageChange / handleSortChange / handleFilterChange | 事件处理 |
| handleSearchModelUpdate / handlePersistReady | 模型同步 / 持久化恢复 |
工具栏 toolbar
| 值 | 说明 |
|------|------|
| false | 关闭工具栏 |
| true | 开启;refresh / zoom / custom 默认开;export / print / headerColor 默认关 |
| 对象 | 单项覆盖 |
| 键 | 默认 | 说明 |
|------|------|------|
| refresh | 开 | 刷新按钮,触发 refresh |
| zoom | 开 | 全屏 |
| custom | 开 | 列设置 |
| export | 关 | 导出 |
| print | 关 | 打印 |
| headerColor | 关 | 表头配色 |
| searchPanel | 开(仅 Page) | 查询条件展开/收起按钮;false 可关 |
<ProPageTable
:toolbar="{ export: true, print: true, zoom: false }"
...
/>分页 pagination
| 值 | 说明 |
|------|------|
| false | 关闭 |
| true | { currentPage: 1, pageSize: 20, total: 0, pageSizes: [10, 20, 50, 100] } |
| 对象 | 覆盖字段 |
常用字段:currentPage、pageSize、total、pageSizes、pagerCount、layouts。
ProPageTable 默认开启分页对象;ProTable 默认关闭。
持久化 storageKey / persist
传入 storageKey 即开启默认持久化(localStorage,键前缀 pro-table:state:)。
| persist 项 | 默认 | 说明 |
|------|------|------|
| column | true | 列显示 / 顺序(vxe custom) |
| sort | true | 排序 |
| filter | true | 表头筛选 |
| pagination | true | pageSize |
| search | true | 搜索模型(Page) |
| searchExpanded | true | 搜索字段展开状态 |
| searchPanel | true | 查询条件模块显隐 |
<ProPageTable
storage-key="user-list"
:persist="{ storage: 'session', search: false }"
...
/>persist: false 关闭全部持久化。实例方法 clearPersist() 可清除当前键状态。
选择 / 批量 / 骨架 / 移动端
选择
<ProTable selection reserve-selection row-key="id" ... />
<!-- 或 selection="radio" -->跨页多选必须:selection 为 checkbox,且 row-key 为字符串字段名,并开启 reserve-selection。
批量操作
<ProPageTable
selection
:batch-actions="{ clearable: true, selectedText: '已选' }"
...
>
<template #batch-actions="{ selected, clear }">
<el-button type="danger" size="mini" @click="onBatchDelete(selected)">
删除 {{ selected.length }} 项
</el-button>
</template>
</ProPageTable>骨架屏 skeleton
| 值 | 说明 |
|------|------|
| false | 关闭 |
| true | { animated: true, onlyEmpty: true }(仅无数据且 loading 时显示) |
| 对象 | rows / animated / onlyEmpty |
移动端卡片 mobileCard
窄屏或容器过窄时自动切卡片列表。
| 值 | 说明 |
|------|------|
| false | 关闭 |
| true | { enabled: true, breakpoint: 768, maxFields: 0 } |
| 对象 | enabled / breakpoint / titleField / maxFields |
树表 / 行内编辑
<ProTable
:data="treeData"
:columns="columns"
:tree-config="{ children: 'children', expandAll: false }"
:edit-config="{ trigger: 'click', mode: 'cell' }"
@edit-save="onEditSave"
/>列上设置 treeNode: true 指定树节点列;editRender: { name: 'input' } 开启该列编辑。
ProSearchForm
可单独使用的搜索表单。
| Prop | 类型 | 默认 | 说明 |
|------|------|------|------|
| value | Object | {} | 表单值(v-model) |
| fields | Array | [] | 搜索字段 |
| title / searchText / resetText | String | 见上 | 文案 |
| expandText / collapseText | String | '展开' / '收起' | 折叠文案 |
| collapsible | Boolean | true | 是否可折叠 |
| defaultExpanded | Boolean | false | 默认展开 |
| collapseVisibleCount | Number | 3 | 收起可见数 |
| storageKey | String | — | 持久化展开状态 |
事件:input、search、reset。
扩展 API
import {
registerValueType,
registerValueTypes,
registerSearchField,
registerSearchFields,
setProTableDefaults,
buildSearchFieldsFromColumns,
createSearchModel,
} from '@hz_yujin/vue2-base-table'
// 自定义搜索控件
registerSearchField('my-picker', MyPickerComponent)
// 全局默认(按需)
setProTableDefaults({ /* ... */ })按需引入
import {
ProPageTable,
ProTable,
ProSearchForm,
ProDialog,
useProTableRequest,
} from '@hz_yujin/vue2-base-table'
import '@hz_yujin/vue2-base-table/style.css'ProDialog
与表格并列使用的弹框封装,不内嵌在 ProTable 中。基于 el-dialog,统一圆角、标题栏与底部操作区样式。
基础用法
<template>
<div>
<el-button type="primary" @click="visible = true">打开</el-button>
<ProDialog
v-model="visible"
title="编辑用户"
size="medium"
:confirm-loading="saving"
@confirm="handleSave"
@cancel="visible = false"
>
<el-form label-width="80px" size="small">
<!-- 表单内容 -->
</el-form>
</ProDialog>
</div>
</template>
<script>
export default {
data() {
return { visible: false, saving: false }
},
methods: {
async handleSave() {
this.saving = true
try {
// await api.save(...)
this.visible = false
} finally {
this.saving = false
}
},
},
}
</script>也可用 :visible.sync="visible" 控制显隐(与 v-model 二选一即可)。
Props
| Prop | 类型 | 默认 | 说明 |
|------|------|------|------|
| value | Boolean | false | 显隐,配合 v-model |
| visible | Boolean | — | 显隐,配合 :visible.sync;传入时优先于 value |
| title | String | '' | 标题文案(可用 title 插槽覆盖) |
| size | String | 'large' | 尺寸预设:small / medium / large / full |
| width | String | — | 自定义宽度,传入后优先于 size |
| top | String | '15vh' | 距顶部距离 |
| modal | Boolean | true | 是否显示遮罩 |
| appendToBody | Boolean | true | 是否插入至 body |
| destroyOnClose | Boolean | false | 关闭时销毁内容 |
| closeOnClickModal | Boolean | false | 点击遮罩是否关闭 |
| closeOnPressEscape | Boolean | true | 按 ESC 是否关闭 |
| showClose | Boolean | true | 是否显示右上角关闭按钮 |
| showFooter | Boolean | true | 是否显示底部栏(有 footer 插槽时也会显示) |
| showCancel | Boolean | true | 是否显示取消按钮 |
| showConfirm | Boolean | true | 是否显示确定按钮 |
| cancelText | String | '取消' | 取消按钮文案 |
| confirmText | String | '确定' | 确定按钮文案 |
| confirmType | String | 'primary' | 确定按钮 el-button type,如 primary / danger |
| confirmLoading | Boolean | false | 确定按钮 loading |
| confirmDisabled | Boolean | false | 确定按钮禁用 |
| beforeClose | Function | — | 关闭前钩子,签名 (done) => void,需自行调用 done() |
| customClass | String | '' | 追加到弹框根节点的自定义 class |
| zIndex | Number | — | 可选。透传 Element Popup(遮罩与弹框同步)。默认不传,由统一起点 + 自动递增;多层弹框请勿写死 |
层级约定
| 场景 | z-index |
|------|---------|
| 表格全屏 | 2900 |
| ProDialog / 遮罩 | 自弹框起点(默认 3000)起由 PopupManager 自动递增 |
| vxe Modal(列设置「恢复默认」等) | 与弹框起点对齐(默认 3000,随 setPopupZIndexBase 抬高) |
| MessageBox | 弹框起点 + 1900(默认 4900) |
| Message / Notification | 弹框起点 + 2000(默认 5000) |
若宿主顶栏 / 抽屉 / 无界遮罩等高于默认起点,在入口抬高即可(MessageBox 会自动跟着抬):
import Vue2BaseTable, {
setPopupZIndexBase,
getPopupLayerZIndex,
} from '@hz_yujin/vue2-base-table'
import '@hz_yujin/vue2-base-table/style.css'
// 方式一:插件选项(推荐)
Vue.use(ElementUI, { zIndex: 12000 })
Vue.use(Vue2BaseTable, { zIndex: 12000 })
// → Dialog 自 12000 起;MessageBox≈13900;Message≈14000
// 方式二:显式 API
setPopupZIndexBase(12000)
const { messageBox } = getPopupLayerZIndex()业务弹层用 ProDialog;删改确认继续用 $confirm / MessageBox。
size 与宽度对照
| size | 宽度 |
|------|------|
| small | 420px |
| medium | 560px |
| large | 720px |
| full | 92% |
Events
| 事件 | 说明 |
|------|------|
| input / update:value | v-model 更新 |
| update:visible | :visible.sync 更新 |
| confirm | 点击确定(不会自动关闭,由业务在逻辑完成后自行将显隐设为 false) |
| cancel | 点击取消(会关闭弹框) |
| open | 打开动画开始前 |
| opened | 打开动画结束后 |
| close | 关闭动画开始前 |
| closed | 关闭动画结束后 |
Slots
| 插槽 | 说明 |
|------|------|
| 默认 | 弹框主体内容 |
| title | 自定义标题区 |
| footer | 自定义底部(覆盖默认取消/确定) |
