npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@qingbing/ts-v3-xz-table

v2.0.18

Published

以 vue3 + element-plus 为基础封装的 table 组件

Downloads

4

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: 编辑组件
  1. 自定义组件各自参考
  2. 对于 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 属性组合使用参考

  1. refreshKey 可加入任意组合, 用于刷新表格
  2. header 使用组合
    1. headers
    2. getHeaders
    3. getHeaders, beforePushCall
    4. getHeaders, cacheKey, cacheDuration(默认1小时), beforePushCall
  3. 表格数据使用组合
    1. data
    2. getData, params
    3. getData, params, pagination
  4. 编辑表格
    1. editConf, 编辑表格
    2. 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>