IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue3 ts element plus table表格二次封装详细步骤 (附参数及类型详细介绍) -> 正文阅读

[JavaScript知识库]vue3 ts element plus table表格二次封装详细步骤 (附参数及类型详细介绍)

前言

因为最近项目中频繁会使用到table表格,所以基于element plus table 做了一个二次封装的组件。

效果图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1. Table 组件封装

src/components/Table/index.vue

<template>
    <div>
        <el-table
            :data="tableData"
            :stripe="_option.stripe"
            :height="_option.height"
            :maxHeight="_option?.maxHeight"
            :size="_option.size"
            :showHeader="_option.showHeader"
            :tooltipEffect="_option.tooltipEffect"
            :row-style="_option.rowStyle"
            @selection-change="handleSelectionChange"
            @row-click="handleRowClick"
            @cell-click="handleCellClick">
            <template v-for="(col, index) in column" :key="index">
                <!---复选框, 序号 (START)-->
                <el-table-column
                    v-if="col.type === 'index' || col.type === 'selection' || col.type === 'expand'"
                    :align="col.align"
                    :label="col.label"
                    :type="col.type"
                    :index="indexMethod"
                    :width="col.width" />
                <!---复选框, 序号 (END)-->
                <!---图片 (START)-->
                <el-table-column
                    v-else-if="col.type === 'image'"
                    :align="col.align"
                    :label="col.label"
                    :width="col.width">
                    <template #default="{ row }">
                        <!-- 如需更改图片size,可自行配置参数 -->
                        <el-avatar :size="50" shape="square" :src="row[col.prop!]" />
                    </template>
                </el-table-column>
                <!---图片 (END)-->
                <!-- 自定义slot (START) -->
                <el-table-column
                    :show-overflow-tooltip="col.showOverflowTooltip"
                    v-else-if="col.slot"
                    :align="col.align"
                    :label="col.label"
                    :width="col.width">
                    <template #default="scope">
                        <slot :name="col.slot" :row="scope.row" :index="scope.$index"></slot>
                    </template>
                </el-table-column>
                <!-- 自定义slot (END) -->
                <!-- 如果传递按钮数组,就展示按钮组 START-->
                <el-table-column
                    :show-overflow-tooltip="col.showOverflowTooltip"
                    v-else-if="col.buttons?.length"
                    :align="col.align"
                    :label="col.label"
                    :width="col.width">
                    <template #default="scope">
                        <el-button-group>
                            <el-button
                                v-for="(btn, index) in col.buttons"
                                size="small"
                                :key="index"
                                :type="btn.type"
                                @click="handleAction(btn.command, scope)"
                                >{{ btn.name }}</el-button
                            >
                        </el-button-group>
                    </template>
                </el-table-column>
                <!-- 如果传递按钮数组,就展示按钮组 END-->
                <!-- 默认渲染列 (START) -->
                <el-table-column
                    :show-overflow-tooltip="col.showOverflowTooltip"
                    v-else
                    :label="col.label"
                    :prop="col.prop"
                    :align="col.align"
                    :width="col.width" />
                <!-- 默认渲染列 (END) -->
            </template>
        </el-table>
        <!-- 分页器 -->
        <div v-if="_option.showPagination" class="mt20">
            <el-pagination
                v-bind="_paginationConfig"
                @size-change="pageSizeChange"
                @current-change="currentPageChange" />
        </div>
    </div>
</template>
<script lang="ts" setup>
interface TableProps {
    tableData: Array<object> // table的数据
    column: Table.Column[] // 每列的配置项
    option?: Table.Option
}
const props = defineProps<TableProps>()
// 设置option默认值,如果传入自定义的配置则合并option配置项
const _option: ComputedRef<Table.Option> = computed(() => {
    const option = {
        stripe: false,
        tooltipEffect: 'dark',
        showHeader: true,
        showPagination: false,
        rowStyle: () => 'cursor:pointer' // 行样式
    }
    return Object.assign(option, props?.option)
})
// 合并分页配置
const _paginationConfig = computed(() => {
    const config = {
        total: 0,
        currentPage: 1,
        pageSize: 10,
        pageSizes: [10, 20, 30, 40, 50, 100],
        layout: 'total, sizes, prev, pager, next, jumper'
    }
    return Object.assign(config, _option.value.showPagination)
})
interface EmitEvent {
    (e: 'selection-change', params: any): void // 当选择项发生变化时会触发该事件
    (e: 'row-click', row: any, column: any, event: Event): void // 当某一行被点击时会触发该事件
    (e: 'cell-click', row: any, column: any, cell: any, event: Event): void // 当某个单元格被点击时会触发该事件
    (e: 'command', command: string | number, row: any): void // 按钮组事件
    (e: 'size-change', pageSize: number): void // pageSize事件
    (e: 'current-change', currentPage: number): void // currentPage按钮组事件
}
const emit = defineEmits<EmitEvent>()
// 自定义索引
function indexMethod(index: number) {
    const tabIndex = index + (_paginationConfig.value.currentPage - 1) * _paginationConfig.value.pageSize + 1
    return tabIndex
}
// 切换pageSize
const pageSizeChange = (pageSize: number) => {
    emit('size-change', pageSize)
}
// 切换currentPage
const currentPageChange = (currentPage: number) => {
    emit('current-change', currentPage)
}
// 按钮组事件
const handleAction = (command: string | number, scope: any) => {
    emit('command', command, scope.row)
}
// 多选事件
const handleSelectionChange = (val: any) => {
    emit('selection-change', val)
}
// 当某一行被点击时会触发该事件
const handleRowClick = (row: any, column: any, event: Event) => {
    emit('row-click', row, column, event)
}
// 当某个单元格被点击时会触发该事件
const handleCellClick = (row: any, column: any, cell: any, event: Event) => {
    emit('cell-click', row, column, cell, event)
}
</script>
<style lang="scss" scoped></style>

2. 页面引用

src/views/table/index.vue

基本表格
<template>
    <div class="p10">
        <h1 class="mb-5 text-base text-gray-100 bg-red-400 p-2 border-4 border-green-400 rounded-md">
            element-plus table表格二次封装 <span class="ml-6">(此标题样式使用Tailwind Css生成)</span>
        </h1>
        <el-card class="box-card mb35">
            <template #header>
                <div class="card-header">
                    <span>基本表格</span>
                </div>
            </template>
            <table
                :column="tableColumn"
                :table-data="tableData"
                :option="option"
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                @selection-change="handleSelection"
                @command="handleAction">
                <template #date="{ row }">
                    <span> {{ row.date }}</span>
                </template>
                <!-- 如果不传入按钮组的数据就使用自定义插槽的方式 -->
                <!-- <template #action="{ row, index }">
                    <div>
                        <el-button type="success">添加</el-button>
                        <el-button type="warning" @click="handleDelete(row, index)">删除</el-button>
                    </div>
                </template> -->
            </table>
        </el-card>
    </div>
</template>
<script lang="ts" setup>
    import { tableColumn } from '@/config/table'
    import { ElMessageBox, ElMessage } from 'element-plus'
    interface User {
        date: string
        name: string
        address: string
    }
    // 基本表格数据
    const tableData: User[] = [
        {
            date: '2016-05-022016-05-022016-05-022016-05-022016-05-02',
            name: '佘太君',
            address: '上海市普陀区金沙江路 1516 弄'
        },
        {
            date: '2016-05-04',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1517 弄'
        },
        {
            date: '2016-05-01',
            name: '王小帅',
            address: '上海市普陀区金沙江路 1519 弄'
        },
        {
            date: '2016-05-03',
            name: '王小呆',
            address: '上海市普陀区金沙江路 1516 弄'
        }
    ]
    const handleSelection = (val: User[]) => {
        console.log('父组件接收的多选数据', val)
    }
    const handleAction = (command: string | number, row: User) => {
        switch (command) {
            case 'edit':
                alert('点击了编辑')
                break
            case 'delete':
                console.log('row', row)
                ElMessageBox.confirm('确认删除吗?', '提示').then(() => {
                    ElMessage(JSON.stringify(row))
                })
                break
            default:
                break
        }
    }
</script>
<style lang="scss" scoped></style>
带有分页的表格
<template>
    <div class="p-5">
        <h1 class="mb-5 text-base text-gray-100 bg-red-400 p-2 border-4 border-green-400 rounded-md">
            element-plus table表格二次封装 <span class="ml-6">(此标题样式使用Tailwind Css生成)</span>
        </h1>
        <!-- 带有分页的表格 -->
        <el-card class="box-card mb35">
            <template #header>
                <div class="card-header">
                    <span>带有分页的表格</span>
                </div>
            </template>
            <easy-table
                :column="tableDemoColumn"
                :table-data="tableDemoList"
                :option="option"
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                @command="handleAction">
                <template #gender="{ row }">
                    <span> {{ row.gender ? '男' : '女' }}</span>
                </template>
            </easy-table>
        </el-card>
    </div>
</template>
<script lang="ts" setup>
    import { tableDemoColumn } from '@/config/table'
    import { ElMessageBox, ElMessage } from 'element-plus'
    import { getDemoList } from '@/service/api/table'
    const route = useRoute()
    const router = useRouter()
    interface User {
        date: string
        name: string
        address: string
    }

    interface State {
        tableDemoList: TableDemoItem[]
        pageInfo: PageInfo
        option: Table.Option
    }
    const state = reactive<State>({
        pageInfo: {
            currentPage: 1,
            pageSize: 10,
            total: 0
        },
        tableDemoList: [],
        option: { showPagination: true, height: 600 }
    })
    const params: TableDemoParams = {
        page: 1,
        pageSize: 10
    }
    watch(
        () => route.query,
        async (newval) => {
            const { page, pageSize } = newval
            params.page = Number(page) || params.page
            params.pageSize = Number(pageSize) || params.pageSize
            const { items, pageInfo } = await getDemoList(params)
            state.tableDemoList = items
            state.option.paginationConfig = pageInfo
        },
        { immediate: true }
    )
    // 改变pageSize
    const handleSizeChange = (pageSize: number) => {
        router.push({
            path: '/components/table',
            query: {
                page: 1,
                pageSize
            }
        })
    }
    // 改变currentPage
    const handleCurrentChange = (page: number) => {
        router.push({
            path: '/components/table',
            query: {
                page,
                pageSize: route.query.pageSize || params.pageSize
            }
        })
    }
    const handleAction = (command: string | number, row: User) => {
        switch (command) {
            case 'edit':
                alert('点击了编辑')
                break
            case 'delete':
                console.log('row', row)
                ElMessageBox.confirm('确认删除吗?', '提示').then(() => {
                    ElMessage(JSON.stringify(row))
                })
                break
            default:
                break
        }
    }
    const { tableDemoList, option } = toRefs(state)
</script>
<style lang="scss" scoped></style>

3.表格配置项

src/config/table.ts 参数可参考下面参数介绍

// 基本表格配置
export const tableColumn = [
    { type: 'selection', width: '50', label: 'No.' },
    { type: 'index', width: '50', label: 'No.' },
    { prop: 'name', label: '名字' },
    { prop: 'date', slot: 'date', label: '日期', showOverflowTooltip: true },
    { prop: 'address', label: '地址', showOverflowTooltip: true },
    {
        width: '120',
        label: '操作',
        buttons: [
            { name: '编辑', type: 'success', command: 'edit' },
            { name: '删除', type: 'danger', command: 'delete' }
        ]
    }
] as Table.Column[]
// 带有分页的表格配置
export const tableDemoColumn = [
    { type: 'index', width: '65', label: 'No.', align: 'center' },
    { prop: 'avatar', type: 'image', label: '头像', width: '100', align: 'center' },
    { prop: 'name', label: '姓名', width: '100' },
    { prop: 'age', label: '年龄', width: '90', align: 'center' },
    { prop: 'gender', label: '性别', width: '90', slot: 'gender', align: 'center' },
    { prop: 'mobile', label: '手机号', width: '180' },
    { prop: 'email', label: '邮箱', showOverflowTooltip: true },
    { prop: 'address', label: '地址', showOverflowTooltip: true },
    {
        width: '120',
        label: '操作',
        buttons: [
            { name: '编辑', type: 'success', command: 'edit' },
            { name: '删除', type: 'danger', command: 'delete' }
        ]
    }
] as Table.Column[]

4.参数类型声明

src/typings/table/index.d.ts 声明为全局的类型,方便使用

// table表格
declare namespace Table {
	type Type = 'selection' | 'index' | 'expand' | 'image'
    type Size = 'large' | 'default' | 'small'
    type Align = 'center' | 'left' | 'right'
    interface ButtonItem {
        name: string,
        command: string | number,
        type?: 'primary' | 'success' | 'warning' | 'danger' | 'info',
    }
    interface Column {
        type?: Type,
        // 对应列的类型。 如果设置了selection则显示多选框; 如果设置了 index 则显示该行的索引(从 1 开始计算); 如果设置了 expand 则显示为一个可展开的按钮
        label: string,
        prop?: string,
        slot?: string
        width?: string,
        align?: Align,
        showOverflowTooltip?: boolean,
        showPagination?: boolea,
        buttons?: ButtonItem[],
    }
    interface Option {
        height?: string | number,
        // Table 的高度, 默认为自动高度。 如果 height 为 number 类型,单位 px;如果 height 为 string 类型,则这个高度会设置为 Table 的 style.height 的值,Table 的高度会受控于外部样式。
        stripe?: boolean, // 是否为斑马纹 table
        maxHeight?: string | number, // Table 的最大高度。 合法的值为数字或者单位为 px 的高度。
        size?: Size // Table 的尺寸
        showHeader?: boolean // 是否显示表头,
        tooltipEffect?: 'dark' | 'light' // tooltip effect 属性
        paginationConfig?: Pagination, // 分页器配置项,详情见下方 paginationConfig 属性,
   	 	rowStyle?: ({ row, rowIndex }) => stirng | object // 行的 style 的回调方法,也可以使用一个固定的 Object 为所有行设置一样的 Style。
    }
    interface Pagination {
        total?: number, // 总条目数
        currentPage: number, // 当前页数,支持 v-model 双向绑定
        pageSize: number, // 每页显示条目个数,支持 v-model 双向绑定
        pageSizes?: number[], // 每页显示个数选择器的选项设置
        layout?: string, // 组件布局,子组件名用逗号分隔
        background?: boolean // 是否为分页按钮添加背景色
    }
}

参数介绍

Table 属性

参数说明类型是否必填默认值
tableDatatable 表格的数据Array<object>
option自定义配置object
column每列配置项object

Option 配置项

参数说明类型是否必填默认值
heightTable 的高度, 默认为自动高度。 如果 height 为 number 类型,单位 px;如果 height 为 string 类型,则这个高度会设置为 Table 的 style.height 的值,Table 的高度会受控于外部样式。string / number
maxHeightTable 的最大高度。 合法的值为数字或者单位为 px 的高度。string / number
size字段名称 对应列内容的字段名large / default /small
showHeader是否显示表头stringtrue
tooltipEffecttooltip effect 属性dark / lightdark
stripe是否为斑马纹 tablebooleanfalse
showPagination是否展示分页器booleanfalse
paginationConfig分页器配置项,详情见下方 paginationConfig 配置,(当 showPagination 为 true,该配置项必传)Pagination
rowStyle行的 style 的回调方法,也可以使用一个固定的 Object 为所有行设置一样的 Style。function({ row, rowIndex }) / object() => ‘cursor:pointer’

本项目中rowStyle需默认设置为cursor:pointer,不需要可删除此默认选项

Column 配置项

参数说明类型是否必填默认值
type对应列的类型。 如果设置了 selection 则显示多选框; 如果设置了 index 则显示该行的索引(从 1 开始计算); 如果设置了 expand 则显示为一个可展开的按钮;如果设置 image,则显示图片。(Column 可以设置多个 type)selection / index / expand / image
label每一列的标题string
prop字段名称 对应列内容的字段名string
slot插槽名称,自定义列的内容 作用域参数为 { row, $index }string
width对应列的宽度string / number
align对齐方式left / center / rightleft
showOverflowTooltip当内容过长被隐藏时显示 tooltipbooleanfalse
buttons按钮组的内容Array<object>

paginationConfig 配置项

参数说明类型是否必填默认值
total总条目数number0
currentPage当前页数,支持 v-model 双向绑定number1
pageSize每页显示条目个数,支持 v-model 双向绑定number10
pageSizes每页显示个数选择器的选项设置number[][10, 20, 30, 40, 50, 100]
layout组件布局,子组件名用逗号分隔string‘total, sizes, prev, pager, next, jumper’
background是否为分页按钮添加背景色booleanfalse

Buttons 配置项

参数说明类型是否必填默认值
name按钮显示的名称string
command派发到 command 回调函数的指令参数string/number
type当前按钮的类型primary / success / warning / danger / info

Table 事件

事件名说明回调参数
selection-change当选择项发生变化时会触发该事件selection
row-click当某一行被点击时会触发该事件row, column, event
cell-click当某个单元格被点击时会触发该事件row, column, cell, event
command点击按钮组某个按钮触发的事件回调command, row
size-changepageSize 改变时触发pageSize
current-changecurrent-change 改变时触发currentPage

其他

此文档只提供基本的封装思路,如需使用到更多的业务场景,可自行扩展。如: 搜索,api 请求等

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-04 22:45:33  更:2022-07-04 22:45:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/11 10:11:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码