@qingbing/ts-v3-xz-table
v2.0.18
Published
以 vue3 + element-plus 为基础封装的 table 组件
Downloads
10
Maintainers
Readme
XzTable 插件介绍
1. 概要说明
1.1 地址
https://gitee.com/duqingbing/ts-v3-package/tree/ts-v3-xz-table
1.2 插件描述
以 vue3 + element-plus 为基础封装的 table 组件
1.3 重要依赖
- @qingbing/ts-v3-cell-edit: ^2.0.7
- @qingbing/ts-v3-operate-button: ^2.0.5
- @qingbing/ts-v3-utils: ^1.0.5
- element-plus: ^2.6.3
- vue: ^3.4.21
1.4 插件安装
# yarn 安装
yarn add @qingbing/ts-v3-xz-table
# npm 安装
npm i @qingbing/ts-v3-xz-table
2. 包说明
2.1 属性说明
| 属性名 | 类型 | 是否必需 | 默认值 | 意义 | | :------------- | :----------------------------------------------------------------------------------- | :------- | :------------ | :-------------------------------------------------------------------------------------- | | refreshKey | number | 否 | - | 表单重新加载标志, 通过 watch 该标志来刷新表格 | | tableConf | TXzTableConf | 否 | {} | element-plus 表格绑定属性, 参考官网 | | editable | boolean | 否 | false | 是否为编辑表格 | | callSave | (params:{row:TRecord,field:string,value:any},callback:(status?:boolean)=>void)=>void | 否 | - | 表格编辑的数据保存函数 | | headers | TXzTableItem[] | 否 | [] | 静态表格配置 | | cacheKey | TKey(string) | 否 | undefined | 对于动态表头设置后会缓存在 localStorage 中 | | cacheDuration | number | 否 | cacheDuration | 动态表头缓存时间(秒) | | getHeaders | TXzTableFetchHeader | 否 | undefined | 获取动态表头函数 | | beforePushCall | TXzTableBeforePushHeader | 否 | undefined | push header-item 之前执行的函数, 主要用户动态表头在缓存的情况下处理函数不能json化的问题 | | data | TRecord[] | 否 | [] | 表格静态数据 | | params | TObject | 否 | {} | 获取动态表格数据时额外提供的查询条件 | | getData | TXzTableFetchData | 否 | undefined | 获取动态表格数据函数, 根据返回结果组件自行决定是否分页 | | pagination | TXzTablePagination | 否 | {} | 分页组件配置 | | components | Record<string, Component> | 否 | [] | 单元格支持组件, 默认会追加 'operate => OperateButton' 组件 |
2.2 属性类型说明
2.2.1 tableConf: 表格配置
// 表格配置, 参数意义参考: https://element-plus.org/zh-CN/component/table.html#table-属性
export type TXzTableConf = {
height?: string | number // 表格高度
maxHeight?: string | number // 表格最大高度
stripe?: boolean
border?: boolean
size?: '' | 'large' | 'default' | 'small'
fit?: boolean
showHeader?: boolean
highlightCurrentRow?: boolean
currentRowKey?: string | number
rowClassName?: string | ((data: { row: any; rowIndex: number }) => string)
rowStyle?: object | Function
cellClassName?:
| string
| ((data: { row: any; column: any; rowIndex: number; columnIndex: number }) => string)
cellStyle?: object | Function
headerRowClassName?: string | ((data: { row: any; rowIndex: number }) => string)
headerRowStyle?: object | Function
headerCellClassName?:
| string
| ((data: { row: any; column: any; rowIndex: number; columnIndex: number }) => string)
headerCellStyle?: object | Function
rowKey?: string | ((row: any) => string)
emptyText?: string
defaultExpandAll?: boolean
expandRowKeys?: object
defaultSort?: object
tooltipEffect?: 'dark' | 'light'
showSummary?: boolean
sumText?: string
summaryMethod?: (data: { columns: any[]; data: any[] }) => string[]
spanMethod?: (data: {
row: any
column: any
rowIndex: number
columnIndex: number
}) => number[] | { rowspan: number; colspan: number } | void
indent?: number
lazy?: boolean
load?: (row: any, treeNode: TreeNode, resolve: (data: any[]) => void) => void
treeProps?: object
tableLayout?: 'fixed' | 'auto'
scrollbarAlwaysOn?: boolean
showOverflowTooltip?: boolean | object
flexible?: boolean
}
2.2.2 editConf: 编辑表格配置
type TXzTableCellEdit = {
/*
这些配置在 表头配置
params?: TObject;
type: TCellEditType;
ops?: TObject;
selectUseEmpty?: boolean;
selectEmptyOps?: {
value: string;
label: string;
};
*/
callSave?: TCellEditCallSave; // 建议配置在组件上
}
2.2.3 headers: 表头配置
type TXzTableItem = {
field: string // 列表表头字段
label: string // 列表表头名称
default?: any // 默认值
tableConf?: TXzTableColumnConf // 单元格绑定属性,参考 element-plus table-column
type?: 'image' | 'component' | 'edit' | 'option' | 'none'
exts?: { // 额外的信息保存
imageConf?: TXzTableImageConf// 图片展示控制, 缩略图点击展示大图
editConf?: TXzTableCellEdit // 元素编辑
component?: { // 组件配置
name: string, // 注册的组件名
conf?: TObject // 组件配置
}
options?: TObject // 选项信息: 标签替换显示 | 编辑表格的 select-options
}
}
2.2.3.1 headers-imageConf: 图片组件
/**
* 图片编辑配置, 参数意义参考: https://element-plus.org/zh-CN/component/image.html#image-attributes
*/
export type TXzTableImageConf = {
fit?: '' | 'fill' | 'contain' | 'cover' | 'none' | 'scale-down', // 图片适应容器框方式
zoomTate?: number, // default 1.2, 图像查看器缩放事件的缩放速率
maxScale?: number, // default 7, 图像查看器缩放事件的最小缩放比例
minScale?: number, // default 0.2, 图像查看器缩放事件的最大缩放比例
closeOnPressEscape?: boolean, // default true, 按下 ESC 关闭 Image Viewer
previewTeleported?: boolean, // default true, image-viewer 是否插入至 body 元素上, false 可能导致 z-index 的错乱
style?: string | TObject, // default 'width: 100px; height: 80px', 样式
}
2.2.3.2 headers-editConf: 编辑组件
/**
* 单元编辑配置, 参数意义参考: https://gitee.com/duqingbing/ts-v3-package/tree/ts-v3-cell-edit
*/
type TXzTableCellEdit = {
type: TCellEditType;
ops?: TObject;
params?: TObject;
selectUseEmpty?: boolean;
selectEmptyOps?: {
value: string;
label: string;
};
callSave?: TCellEditCallSave;
}
2.2.3.3 headers-component: 编辑组件
- 自定义组件各自参考
- 对于 operateButton 配置参考: https://gitee.com/duqingbing/ts-v3-package/tree/ts-v3-operate-button/
2.2.3.4 headers-options: 选项 value
配置成对象即可: {key: label}
2.2.4 getHeaders: 获取表头动态数据函数
/**
* 获取表格头的函数类型
*/
export type TXzTableFetchHeader = (callback: (item: TXzTableItem[]) => void, cacheKey?: TKey) => void
/**
* 对于动态表头, 项目在 push 到 Header 之前可做最后一次修改, 主要时添加 执行函数之类的操作, 因为对于函数, json 字符串保存不了
*/
export type TXzTableBeforePushHeader = (item: TXzTableItem) => TXzTableItem
2.2.5 getData: 编辑表格动态数据函数
/**
* 获取表格数据的函数类型, 可为分页或不分页数据
*/
export type TXzTableFetchData = (callback: (res: TRecord[] | TPagingData<TRecord>) => void, params?: TObject) => void
2.2.2 pagination: 分页组件配置
// 分页配置, 参数意义参考: https://element-plus.org/zh-CN/component/pagination.html#属性
export type TXzTablePagination = {
small?: boolean
background?: boolean
pageSize?: number
defaultPageSize?: number
total?: number
// pageCount?: number
pagerCount?: number
currentPage?: number
defaultCurrentPage?: number
layout?: string,
pageSizes?: number[],
prevText?: string,
prevIcon?: string | Component
nextText?: string,
nextIcon?: string | Component
disabled?: boolean
hideOnSinglePage?: boolean
}
2.3 属性组合使用参考
- refreshKey 可加入任意组合, 用于刷新表格
- header 使用组合
- headers
- getHeaders
- getHeaders, beforePushCall
- getHeaders, cacheKey, cacheDuration(默认1小时), beforePushCall
- 表格数据使用组合
- data
- getData, params
- getData, params, pagination
- 编辑表格
- editConf, 编辑表格
- editConf, editable, 可制作可控编辑的表格
3. 表头项目构建工具
提供一个创建表头项目的工具,主要理解其定义要点,然后按规则天如相对数据即可
3.1 工具类型
// 特定类型选项
const options = {
yesNo: {
"0": "否",
"1": "是",
},
sex: {
"0": "秘",
"1": "男",
"2": "女",
},
forbidden: {
"0": "启用",
"1": "禁用",
},
enable: {
"0": "禁用",
"1": "启用",
},
opened: {
"0": "关闭",
"1": "开启",
},
deleted: {
"0": "正常",
"1": "已删除",
},
}
type TDataType =
'image' | 'component' | 'edit' | 'option' | 'none' // 原有类型
| 'text' | 'number' | 'textarea' | 'switch' | 'select' // 编辑类型
| 'yesNo' | 'sex' | 'forbidden' | 'enable' | 'opened' | 'deleted' // 特定状态类型
/**
* 表头创建工具
* field: 表头字段
* label: 表头标题
* dataType: 表头书记类型
* exts: 扩展数据
*/
export default (field: string, label: string, dataType: TDataType, exts?: {
default?: any // 默认值
tableConf?: TXzTableColumnConf // 单元格绑定属性,参考 element-plus table-column
isEdit?: boolean // 是否属于编辑类型, 默认 false, 针对特定状态数据有效: 'yesNo' | 'sex' | 'forbidden' | 'enable' | 'opened' | 'deleted'
// 额外信息
imageConf?: TXzTableImageConf// 图片展示控制, 缩略图点击展示大图
editConf?: Omit<TXzTableCellEdit, 'type'> & {
type?: TCellEditType
}// 元素编辑
component?: { // 组件配置
name: string, // 注册的组件名
conf?: TObject // 组件配置
}
options?: TObject // 选项信息: 标签替换显示 | 编辑表格的 select-options
}): TXzTableItem
3.2 工具使用
const headers: TXzTableItem[] = [
XzTableItemMachine('_idx', "序号", 'none', {
tableConf: {
width: "80",
fixed: "left",
}
}),
XzTableItemMachine('avatar', '用户头像', 'image', {
tableConf: {
width: "200",
align: "center",
}
}),
XzTableItemMachine('username', '用户名', 'text', {
tableConf: {
width: "160",
align: "left",
}
}),
XzTableItemMachine('sex', '性别', 'sex', {
default: '0',
isEdit: true,
tableConf: {
width: "100",
}
}),
XzTableItemMachine('age', '年龄', 'number', {
tableConf: {
width: "100",
align: "center",
}
}),
XzTableItemMachine('address', '地址', 'textarea', {
tableConf: {
align: "left",
minWidth: 200,
}
}),
XzTableItemMachine('is_admin', '管理员', 'switch', {
default: 0,
tableConf: {
align: "left",
minWidth: 200,
}
}),
XzTableItemMachine('operate', '操作', 'component', {
tableConf: {
fixed: "right",
align: "left",
minWidth: 300,
},
component: {
name: "operate",
conf: {
isButton: true,
buttons: [
{
type: 'view',
handle: (row: TRecord) => {
console.log(row);
}
}, {
type: 'edit',
handle: (row: TRecord) => {
console.log(row);
}
},
{
type: 'delete',
handle: (row: TRecord, successCall: (msg: string) => void, failureCall: (msg: string) => void) => {
successCall('删除成功')
refreshTable()
}
}
]
}
},
}),
]
4. 示例
4.1 全局注册使用
- 一旦注册,
XzTable
作为组件全局通用 - 使用方法参考 3.2 模板组件使用, 去掉组件导入的语句即可
// main.ts
import { XzTablePlugin } from '@qingbing/ts-v3-xz-table'
app.use(XzTablePlugin, {
name: 'XzTable',
options: {}
})
4.2 模板组件使用
<template>
<h2>无数据表格</h2>
<XzTable :headers="headers" />
<h2>表格编辑</h2>
<XzTable :headers="headers1" :data="data" :refreshKey="refreshKey" :editable="editable" :callSave="callSave" />
<h2>动态表头</h2>
<XzTable :getHeaders="getHeaders" :beforePushCall="beforePushCall" :data="data" />
<h2>动态表头 + 动态表格</h2>
<XzTable :getHeaders="getHeaders" :beforePushCall="beforePushCall" :getData="getData" :refreshKey="refreshKey" />
<h2> 动态表格 + 表格编辑</h2>
<XzTable :headers="headers" :getData="getData" :refreshKey="refreshKey" :editable="editable" :callSave="callSave" />
<h2>动态表头(缓存) + 动态表格(分页)</h2>
<XzTable :getHeaders="getHeaders" :beforePushCall="beforePushCall" cacheKey="test" :getData="getPaginationData"
:params="queryData" :refreshKey="refreshKey" :pagination="pagination" />
<el-form :inline="true" :model="queryData">
<el-form-item label="用户名">
<el-input v-model="queryData.username" placeholder="输入用户名" clearable />
</el-form-item>
<el-form-item>
<el-button type="warning" @click="handleCellEdit">编辑</el-button>
<el-button type="primary" @click="onSubmit">查询</el-button>
</el-form-item>
</el-form>
<h2>表格编辑 + 动态表格(分页)</h2>
<XzTable :headers="headers" :getData="getPaginationData" :params="queryData" :refreshKey="refreshKey"
:pagination="pagination" :editable="editable" :callSave="callSave" />
</template>
<script lang="ts" setup>
import { TXzTableBeforePushHeader, TXzTableCallSave, TXzTableFetchData, TXzTableFetchHeader, TXzTableItem, TXzTablePagination } from "@qingbing/ts-v3-xz-table"
import type { TObject, TRecord } from "@qingbing/ts-v3-utils"
import { randomInt } from "@qingbing/ts-v3-utils"
import { XzTable, XzTableItemMachine } from "@qingbing/ts-v3-xz-table"
import { reactive, ref } from 'vue'
import { ExMessage } from "@qingbing/ts-v3-element-plus"
import request from "axios";
const refreshKey = ref(0);
const refreshTable = () => {
refreshKey.value++
}
/**
* 表格编辑保存函数
*/
const callSave: TXzTableCallSave = (params: { row: TRecord, field: string, value: any }, callback: (status?: boolean) => void) => {
console.log(params);
const state = !!randomInt(2, 0) // 控制是否操作成功
// do something
if (!state) {
ExMessage.error("哦或, 保存失败了!")
}
callback(state)
}
const pagination = reactive<TXzTablePagination>({});
const headers1: TXzTableItem[] = [
{
field: "_idx",
label: "序号",
tableConf: {
width: "80",
fixed: "left",
}
},
{
field: "avatar",
label: "用户头像",
default: '',
tableConf: {
width: "200",
align: "center",
},
type: 'image',
exts: {
}
},
{
field: "username",
label: "用户名",
default: '-',
tableConf: {
width: "160",
align: "left",
},
type: 'edit',
exts: {
editConf: {
"type": "text",
}
}
},
{
field: "sex",
label: "性别",
default: '0',
tableConf: {
width: "100",
},
type: 'edit',
exts: {
editConf: {
"type": "select",
'ops': {
options: {
"0": "秘",
"1": "男",
"2": "女",
},
}
},
}
},
{
field: "age",
label: "年龄",
default: 0,
tableConf: {
width: "100",
align: "center",
},
type: 'edit',
exts: {
editConf: {
type: "number"
},
}
},
{
field: "address",
default: '-',
label: "地址",
tableConf: {
align: "left",
minWidth: 200,
},
type: 'edit',
exts: {
editConf: {
type: "textarea"
},
}
},
{
field: "is_admin",
default: 0,
label: "管理员",
tableConf: {
align: "left",
minWidth: 200,
},
type: 'edit',
exts: {
editConf: {
type: "switch"
},
}
},
{
field: "operate",
label: "操作",
default: '',
tableConf: {
fixed: "right",
align: "left",
minWidth: 300,
},
type: 'component',
exts: {
component: {
name: "operate",
conf: {
isButton: true,
buttons: [
{
type: 'view',
handle: (row: TRecord) => {
console.log(row);
}
}, {
type: 'edit',
handle: (row: TRecord) => {
console.log(row);
}
},
{
type: 'delete',
handle: (row: TRecord, successCall: (msg: string) => void, failureCall: (msg: string) => void) => {
successCall('删除成功')
refreshTable()
}
}
]
}
},
}
},
]
const headers: TXzTableItem[] = [
XzTableItemMachine('_idx', "序号", 'none', {
tableConf: {
width: "80",
fixed: "left",
}
}),
XzTableItemMachine('avatar', '用户头像', 'image', {
tableConf: {
width: "200",
align: "center",
}
}),
XzTableItemMachine('username', '用户名', 'text', {
tableConf: {
width: "160",
align: "left",
}
}),
XzTableItemMachine('sex', '性别', 'sex', {
default: '0',
isEdit: true,
tableConf: {
width: "100",
}
}),
XzTableItemMachine('age', '年龄', 'number', {
tableConf: {
width: "100",
align: "center",
}
}),
XzTableItemMachine('address', '地址', 'textarea', {
tableConf: {
align: "left",
minWidth: 200,
}
}),
XzTableItemMachine('is_admin', '管理员', 'switch', {
default: 0,
tableConf: {
align: "left",
minWidth: 200,
}
}),
XzTableItemMachine('operate', '操作', 'component', {
tableConf: {
fixed: "right",
align: "left",
minWidth: 300,
},
component: {
name: "operate",
conf: {
isButton: true,
buttons: [
{
type: 'view',
handle: (row: TRecord) => {
console.log(row);
}
}, {
type: 'edit',
handle: (row: TRecord) => {
console.log(row);
}
},
{
type: 'delete',
handle: (row: TRecord, successCall: (msg: string) => void, failureCall: (msg: string) => void) => {
successCall('删除成功')
refreshTable()
}
}
]
}
},
}),
]
const beforePushCall: TXzTableBeforePushHeader = (item: TXzTableItem): TXzTableItem => {
if (item.type == 'component' && item.field == 'operate') {
item.exts = item.exts ?? {}
item.exts.component = {
name: "operate",
conf: {
isButton: true,
buttons: [
{
type: 'view',
handle: (row: TRecord) => {
console.log(row);
}
}, {
type: 'edit',
handle: (row: TRecord) => {
console.log(row);
}
},
{
type: 'delete',
handle: (row: TRecord, successCall: (msg: string) => void, failureCall: (msg: string) => void) => {
successCall('删除成功')
refreshTable()
}
}
]
}
}
}
return item;
}
const getHeaders: TXzTableFetchHeader = (cb, key) => {
request.create({
baseURL: 'http://mock.qiyezhu.net/mock/64e35b8e4a2b7b001dd2e4ec/example/table-header', // 默认就是 "/",
timeout: 5000, // 5000毫秒,5秒
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
})
.post('/', { key })
.then(res => {
cb(res.data.data)
})
.catch(err => err)
}
const data: TRecord[] = [
{
id: 1,
username: 'qingbing',
sex: '2',
age: 20,
is_admin: 1,
address: "成都"
},
{
id: 2,
username: 'yongjing',
sex: '0',
age: 18,
is_admin: 1,
address: "邻水",
avatar: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg',
}
]
// 编辑控制按钮
const editable = ref(true)
const handleCellEdit = () => {
editable.value = !editable.value
}
const queryData = reactive<TRecord>({
username: "qingbing"
})
const getData: TXzTableFetchData = (cb, params?: TObject) => {
request.create({
baseURL: 'http://mock.qiyezhu.net/mock/64e35b8e4a2b7b001dd2e4ec/example/table-data', // 默认就是 "/",
timeout: 5000, // 5000毫秒,5秒
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
})
.post('/', params)
.then(res => cb(res.data.data))
.catch(err => err)
}
const getPaginationData: TXzTableFetchData = (cb, params?: TObject) => {
request.create({
baseURL: 'http://mock.qiyezhu.net/mock/64e35b8e4a2b7b001dd2e4ec/example/table-pagination-data', // 默认就是 "/",
timeout: 5000, // 5000毫秒,5秒
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
})
.post('/', params)
.then(res => cb(res.data.data))
.catch(err => err)
}
const onSubmit = () => {
refreshTable()
}
</script>