在 Vue2 项目中,使用 Element-ui 组件库的 Table 表格组件进行业务开发是常见的需求。为了提高开发效率,我们可以对 Table 组件进行二次封装,使其成为一个通用业务表格。本文将详细介绍如何实现这一过程。
一、引言
在业务开发中,表格组件是不可或缺的工具。为了提升开发效率和代码的可维护性,我们对 Element-ui 的 Table 组件进行了深度二次封装,打造了一个功能丰富的通用业务表格组件。该组件不仅具备以下核心特性,还预留了扩展空间,以满足更复杂的业务需求:
- 灵活的插槽机制:提供默认插槽和多个自定义插槽,轻松实现功能扩展和个性化内容渲染;
- 完善的分页功能:集成分页控件,支持页码和页大小的切换,方便数据管理和浏览;
- 树形结构支持:能够展示层级关系的数据,适用于需要树形展示的场景;
- 行点击响应:内置行点击事件,方便用户进行行级别的交互操作;
- 选择功能:支持单选或多选模式,轻松实现表格行的选择事件处理;
- 更多扩展特性:预留接口和配置项,支持排序、筛选、自定义列渲染等高级功能,以适应多样化的业务场景。
通过这些特性,我们的通用业务表格组件不仅简化了开发流程,还极大地提高了代码的复用性和项目的整体效率。
接下来,我们将详细介绍如何实现这一通用业务表格的封装。
二、封装步骤
步骤一:创建通用表格组件结构
- 创建组件文件 :在 Vue 项目中创建一个名为
CommonTable.vue
的文件。 - 定义组件模板 :在
<template>
标签内,定义表格的结构,包括表格头部、主体和分页。
html
<template>
<div class="table-main">
<!-- 表格头部 操作按钮 -->
<div class="table-header">
<div class="header-button-lf">
<slot name="tableHeader"/>
</div>
<div class="header-button-ri">
<slot name="toolButton"/>
</div>
</div>
<!-- 表格主体 -->
<el-table
ref="table"
v-bind="$attrs"
:data="tableData"
:header-cell-style="cellStyle"
@row-click="rowClick"
:border="border"
:rowKey="rowKey"
:height="height"
:lazy="lazy"
:tree-props="treeProps"
:max-height="maxHeight"
@selection-change="selectionChange"
>
<!-- 默认插槽 -->
<slot/>
<template v-for="(item, index) in columns">
<el-table-column
v-if="item.prop !== 'operation'"
:key="index"
v-bind="item"
:align="item.align? item.align : 'center'"
>
<template v-slot:default="scope" v-if="item.slotName">
<!-- 这里展示 自定义 插槽内容 -->
<slot :name="item.slotName" v-bind="scope"/>
</template>
<template v-if="item.children">
<el-table-column
v-for="(child, iex) in item.children"
:key="iex"
v-bind="child"
:align="item.align? item.align : 'center'"
>
<template v-slot:default="scope" v-if="item.slotName">
<!-- 这里展示 自定义 插槽内容 -->
<slot :name="item.slotName" v-bind="scope"/>
</template>
</el-table-column>
</template>
</el-table-column>
<el-table-column
v-if="item.prop === 'operation'"
:key="index"
v-bind="item"
:align="item.align? item.align : 'center'"
>
<template v-slot:default="scope">
<!-- 这里展示 operation 插槽内容 -->
<slot name="operation" v-bind="scope"/>
</template>
</el-table-column>
</template>
<template #empty>
<el-empty :image-size="300" description="暂无数据"></el-empty>
</template>
</el-table>
<!-- 分页组件 -->
<div class="pagination">
<el-pagination
v-if="pagination"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageParam.pageNum"
:page-sizes="[10, 20, 30, 40, 50, 100]"
:page-size="pageParam.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
/>
</div>
</div>
</template>
表格头部容器 .table-header
这是一个包裹所有头部内容的容器
操作按钮区域 .header-button-lf
与 .header-button-ri
这个区域用于放置表格的头部操作按钮,它通过一个名为 tableHeader
yu toolButton
的插槽来实现内容的自定义。这意味着在使用 CommonTable
组件时,你可以通过这个插槽插入任何自定义的头部内容,比如搜索框、筛选器等。
表格主体 以下是对 <el-table>
组件及其示例属性的讲解:
ref="table"
:为表格设置引用名称,方便在 Vue 组件中通过this.$refs.table
访问表格实例。v-bind="$attrs"
:将父组件传递给子组件的所有非 prop 属性绑定到<el-table>
上,使得可以传递更多属性。:data="tableData"
:绑定表格数据,tableData
是一个数组,数组中的每个对象代表表格的一行。:header-cell-style="cellStyle"
:自定义表头单元格的样式。@row-click="rowClick"
:监听行点击事件,当点击某一行时触发rowClick
方法。:border="border"
:设置表格是否带有边框。:rowKey="rowKey"
:行的 key,用于优化渲染。:height="height"
:表格的高度,如果设置了这个属性,表格会固定高度并出现滚动条。:lazy="lazy"
:是否懒加载子节点数据。:tree-props="treeProps"
:树形表格的配置选项。:max-height="maxHeight"
:表格的最大高度。@selection-change="selectionChange"
:当选择项发生变化时会触发这个事件。
插槽 <slot/>
这是一个默认插槽,允许你在 <el-table>
组件内部插入任何内容,比如自定义的列或者行。
列的循环渲染 使用 v-for
指令循环 columns
数组,为每个列定义 <el-table-column>
组件。
v-if="item.prop !== 'operation'"
:判断当前列是否为操作列,如果不是,则渲染常规列。:key="index"
:为每个列设置唯一的 key 值,通常是列的索引。v-bind="item"
:将列的配置对象绑定到<el-table-column>
上。:align="item.align? item.align : 'center'"
:设置列的对齐方式,默认为居中。
自定义插槽内容 如果列配置中有 slotName
属性,则表示该列需要自定义渲染内容。使用 <slot :name="item.slotName" v-bind="scope"/>
插槽来展示自定义内容。
子列的渲染 如果列配置中有 children
属性,表示这是一个分组列,需要递归渲染子列。
操作列的渲染 如果列的 prop
属性值为 'operation'
,则渲染操作列。操作列通常包含对当前行的操作按钮。
<slot name="operation" v-bind="scope"/>
:使用名为operation
的插槽来展示操作按钮。
空状态插槽 使用 #empty
插槽来定义当表格没有数据时的展示内容。这里使用了 <el-empty>
组件来显示"暂无数据"的信息
步骤二:定义组件的 props 和 events
- 定义 props :在
<script>
标签内的export default
对象中,定义组件接收的属性。 - 定义 events :同样在
<script>
标签内,定义组件触发的事件。
在 Vue 组件中,props
和 events
是组件与外部环境通信的关键机制。以下是对 CommonTable
组件中定义的 props
和 events
的详细讲解:
html
<script>
export default {
name: 'CommonTable',
props: {
lazy: {
type: Boolean,
default: false
},
treeProps: {
type: Object,
default() {
return {}
}
},
rowKey: {
type: String,
default: ''
},
height: {
type: [String, Number],
default: '100%'
},
// 表格最高高度
maxHeight: {
type: [String, Number],
default: '100%'
},
// 表格边框
border: {
type: Boolean,
default: true
},
// 表格数据
tableData: {
type: Array,
default() {
return [];
}
},
// 表格列
columns: {
type: Array,
default() {
return [];
}
},
// 表格分页组件 ==> 非必传(默认为true)
pagination: {
type: Boolean,
default: true
},
total: {
type: Number,
default: 0
},
// 表格表头样式
cellStyle: {
type: Object,
default() {
return {};
},
required: false
}
},
data() {
return {
// 分页参数
pageParam: {
pageSize: 10,
pageNum: 1
}
};
},
methods: {
rowClick(row) {
this.$emit("rowClick", row)
},
// 表格多选
selectionChange(val) {
this.$emit('selectionChange', val);
},
// 每页条数
handleSizeChange(val) {
this.pageParam.pageSize = val;
this.pageParam.pageNum = 1; // 切换每页显示条数时,将页码重置为 1
this.$emit('upPage', this.pageParam);
},
// 当前页
handleCurrentChange(val) {
this.pageParam.pageNum = val;
this.$emit('upPage', this.pageParam);
}
}
};
</script>
Props
props
是组件的自定义属性,允许父组件向子组件传递数据。
-
lazy
:指示表格是否开启懒加载,懒加载通常用于树形表格或大量数据的分页加载。 -
treeProps
:当表格为树形表格时,该属性用于配置树形表格的属性,如子节点键名等。 -
rowKey
:表格行的 key 值,用于优化渲染性能,特别是在进行排序或筛选操作时。 -
height
:表格的高度,可以是像素值或百分比。 -
maxHeight
:表格的最大高度,当内容超出此高度时,将显示滚动条。 -
border
:是否显示表格的边框。 -
tableData
:表格的数据源,每个数组元素代表表格的一行。 -
columns
:表格的列配置,数组中的每个对象定义了列的属性,如列名、数据字段等。 -
pagination
:是否显示分页组件。 -
total
:表格数据的总条数,用于分页组件计算总页数。 -
cellStyle
:自定义表头单元格的样式。
Events
events
是组件的自定义事件,允许子组件向父组件发送消息或通知。
-
rowClick
:当表格的某一行被点击时触发,传递被点击的行数据作为参数。 -
selectionChange
:当表格的选择项发生变化时触发,传递当前选择的行数据数组作为参数。 -
upPage
:当分页参数发生变化时触发,传递当前的pageParam
对象作为参数,该对象包含pageSize
和pageNum
属性。
Methods
以下是组件内部定义的方法,用于处理事件和逻辑:
-
rowClick(row)
:当行被点击时调用,触发rowClick
事件,并将当前行数据传递给父组件。 -
selectionChange(val)
: 当表格的选择项发生变化时调用,触发selectionChange
事件,并将选择的行数据数组传递给父组件。 -
handleSizeChange(val)
:当分页组件的每页显示条数发生变化时调用,更新pageParam
对象,并触发upPage
事件。 -
handleCurrentChange(val)
:当分页组件的当前页码发生变化时调用,更新pageParam
对象,并触发upPage
事件。
通过这些 props
和 events
,CommonTable
组件可以灵活地接收外部数据,同时也能够将内部状态和事件通知给外部,从而实现组件的复用和高度定制化。
CommonTable 组件的使用
js
<template>
<CommonTable
:tableData="data"
v-loading="loading"
:columns="columns"
:total="total"
row-key="id"
:lazy="true"
:treeProps="{children: 'children', hasChildren: 'hasChildren'}"
@upPage="getUpPage"
@selectionChange="handleSelectionChange"
>
<template #toolButton>
<el-button class="filter-item" size="mini" type="primary" @click="add">添加</el-button>
</template>
<template #operation="scope">
<el-button size="mini" type="text" @click="edit(scope.row)">编辑</el-button>
<el-button size="mini" type="text" @click="copy(scope.row)">复制</el-button>
<el-button size="mini" type="text">发布</el-button>
<el-button size="mini" type="text">下架</el-button>
<el-button size="mini" type="text">删除</el-button>
</template>
<template #jobTest="scope">
<span>{{scope.row.jobTest}} </span>
</template>
<template #Status="scope">
<span>
{{scope.row.Status === '00'?'未发布':(scope.row.Status ==='01'?'测评中'(scope.row.Status === '02'?'已结束':'已下架'))}}
</span>
</template>
<template #operation="scope">
<el-button type="text" @click="checkOut('查看', scope.row)">查看</el-button>
<el-button type="text" @click="checkOut('审核', scope.row)">审核</el-button>
</template>
</CommonTable>
</template>
export default {
data(){
return {
multipleSelection: [],
pageParam: {
pageNum: 1, // 当前页码
pageSize: 10 // 每页显示的数据条数
}
columns: [
{type: 'selection', minWidth: 50},
{prop: 'Account', label: '账号', minWidth: 300},
{prop: 'Name', label: '名称', minWidth: 200},
{prop: 'Time', label: '最近登录时间', minWidth: 300},
{prop: 'jobTestName', label: '测评标题', minWidth: 160,slotName: 'jobTest'},
{prop: 'Status', label: '发布状态', minWidth: 100,slotName: 'Status'},
{
prop: 'publish',
label: '审核状态',
minWidth: 110,
formatter: function (row, column, cellValue) {
const option = shzt.find((opt) => opt.value == cellValue);
return option ? option.label : cellValue;
}
},
{
prop: 'accountStatus',
label: '账号状态',
minWidth: 100,
formatter: function (row, column, cellValue) {
switch (cellValue) {
case '01':
return '已启用';
default:
return '已挂起';
}
}
},
{prop: 'operation', label: '操作', fixed: 'right', minWidth: 100}
]
}
},
methods: {
// 查询按钮
searchData() { },
// 查看 审核
checkOut(val, row) { },
getUpPage(pageParam) {
this.pageParam = pageParam;
this.searchData();
},
// 选中数据
handleSelectionChange(val) {
this.multipleSelection = val
},
}
}
这段代码展示了如何在 Vue 组件中使用 ShareTable
组件,这是一个经过二次封装的表格组件,用于展示和操作数据。以下是对代码的详细解释:
CommonTable
组件被用于显示表格数据,并提供了分页、加载状态、列配置等功能。以下是对 CommonTable
组件属性和插槽的说明:
columns
数组定义了表格的列配置,包括列的类型、属性、标签、宽度、对齐方式等。还使用了formatter
函数来格式化特定列的显示值,例如将账号状态码转换为文字描述。:tableData="data"
:绑定表格数据源。v-loading="loading"
:绑定加载状态,用于显示或隐藏加载动画。:columns="columns"
:绑定表格列配置。:total="total"
:绑定表格数据的总条数,用于分页。row-key="id"
:指定表格行的唯一键值,用于树形表格或虚拟滚动。:lazy="true"
:启用懒加载,适用于树形表格。:treeProps="{children: 'children', hasChildren: 'hasChildren'}"
:配置树形表格的子节点属性。@upPage="getUpPage"
:监听分页参数变化的事件。@selectionChange="handleSelectionChange"
:监听表格选择项变化的事件。#toolButton
:在表格头部插入工具按钮,如添加、删除等。#operation
:在表格每行的操作列插入操作按钮,如编辑、删除等。#jobTest
、#Status
:自定义列内容的显示。#operation
插槽中,定义了多个操作按钮,如查看、审核、启用、挂起等
下面是 .table-main
组件的样式,包括表格主体、表格头部和分页器的布局与样式。
scss
<style lang="scss" scoped>
.table-main {
height: 100%;
display: flex;
flex-direction: column;
.table-header {
display: flex;
margin: 10px 0;
justify-content: space-between;
}
.el-table {
flex: 1;
}
.pagination {
width: 100%;
padding: 15px 0;
background-color: #fff;
}
}
</style>
<style>
/* 限制 el-tooltip 内容的宽度并允许文本换行 */
.el-tooltip__popper {
max-width: 400px; /* 你可以根据需要调整这个值 */
white-space: normal !important;
}
/* 确保 tooltip 中的文字能够正确换行 */
.el-tooltip__popper p,
.el-tooltip__popper div {
white-space: normal !important;
}
</style>
总结
这段代码是一个典型的 Vue 组件使用示例,它展示了如何利用 CommonTable
组件的属性、事件和插槽来构建一个具有丰富功能的表格界面。通过这种方式,可以轻松地对表格进行定制,以适应不同的业务场景和需求。打造一个功能丰富的通用业务表格组件。在实际项目中,我们可以根据业务需求调整和扩展这个组件,从而提高开发效率和代码复用性。