前言:项目中涉及到N个表格,并且功能样式类似,一个一个的写,代码堆积如山,尤其是字段多的时候,封装之路势在必行。
结尾附上gittee地址
维护内容1-1:跨页选择bug修复
⚠️⚠️⚠️⚠️ 此版本为1.0 ⚠️⚠️⚠️⚠️
后续会持续更新功能
看看图:
一、父组件使用
1. html部分
<!--
如果涉及到 跨页选择 需要绑定表格数据的唯一值,如果没有就不需要写了
:rowKey="row => row.唯一值"
-->
<public-table
ref="myTable"
:rowKey="row => row.id"
:tableData="tableData"
:columns="columns"
:configFlag="tableConfig"
:pageValue="pageValue"
@sizeChange="sizeChange"
@currentChange="currentChange"
@handleSelectionChange="selectChange"
>
<!-- 操作列 -->
<template slot="operation" slot-scope="{ scope }">
<el-button type="text" size="small" @click="edit(scope.row)">修改</el-button>
<el-button type="text" size="small" @click="remove(scope.row)">删除</el-button>
</template>
</public-table>
2. js部分
这里注意,columns的配置可以单独拆分出去写成一个js文件,这样代码会更清晰简洁,如下代码注释注意
import PublicTable from '../publicTable.vue';
export default {
components: { PublicTable },
watch: {
// 因为没涉及后台,这是自己写的监听表格数组长度给total赋值,项目里就通过请求给total赋值即可
'tableData.length': {
handler(total) {
this.pageValue.total = total;
},
immediate: true,
},
},
data() {
return {
getTableData: [
{
id: '001',
name: 'LiMing',
gender: '1',
born: '1995-12-20',
height: '180',
personalIntro:
'曾毕业于北京科技大学,14年涂鸦实习,16年任职阿里,担任leader,对标P6+',
property: '32000000',
},
{
id: '002',
name: 'Jenny',
gender: '0',
born: '1997-09-03',
height: '163.256',
personalIntro:
'曾毕业于哈弗大学,20年加州伊布丹公司实习,22年来中国深造,担任河北工业大学信息技术系副主任',
property: '35000000',
},
{
id: '003',
name: 'Danny',
gender: '1',
born: '未知',
height: '230.299',
personalIntro:
'我是一只恐龙🦕,我来自5000万年前,我的家人都没有了,我的尾巴有三米长,皮肤绿色,我喜欢戴帽子',
property: '0',
},
],
tableData: [],
// 这里total必须放到pageValue里,如果想放在其他地方,需要在publicTable中更改el-pagination中传参
pageValue: {
pageNum: 1,
pageSize: 10,
total: 0,
},
// 表格配置项和表头信息都可以拆出去,创建一个js文件,这样你的代码会更清晰明了
// export const tableConfig = { ... }
// export const tableColumns = [ ... ]
// 父组件import {tableColumns , tableConfig} from './XXX.js'
// data(){
// return {
// tableConfig:tableConfig,
// columns:tableColumns
// }
// }
// 表格配置项,看个人需求添加
tableConfig: {
needPage: true, // 是否需要分页
index: true, // 是否需要序号
selection: true, // 是否需要多选
reserveSelection: false, // 是否需要支持跨页选择
indexFixed: 'left', // 序号列固定
},
// 表格表头信息
columns: [
{
label: '姓名',
fieldIndex: 'name',
width: '100px',
// fixed: 'left', // 固定列
},
{
label: '性别', // 后台返回的数据是0 和 1,0 代表女生
fieldIndex: 'gender',
type: 'statMap',
options: [
{ value: '1', label: '男' },
{ value: '0', label: '女' },
],
},
{
label: '出生日期',
fieldIndex: 'born',
sortable: true, // 此属性可以设置排序
},
{
label: '身高(cm)',
fieldIndex: 'height',
type: 'tofix2', // 会把身高四舍五入170.235 => 170.24 170 => 170.00
sortable: true,
},
{
label: '个人经历介绍',
fieldIndex: 'personalIntro',
showOverFlowTooltip: true, // 是否需要内容过长隐藏并且,鼠标移入有提示信息
},
{
label: '个人资产',
fieldIndex: 'property',
type: 'money', // 会把金额搞成 1,234,567,890
},
// ⚠️⚠️⚠️⚠️⚠️⚠️ 操作列 ⚠️⚠️⚠️⚠️⚠️⚠️
{
label: '操作',
slotname: 'operation',
width: '100',
fixed: 'right',
},
],
};
},
mounted() {
this.getData();
},
3. methods方法。如下都是示例,如果el-table组件库中的方法封装里没有,可以自行在publictable.vue文件中添加,或者评论留言
methods: {
getData() {
let t = setTimeout(() => {
this.tableData = this.getTableData;
}, 1000);
},
// this.$refs.myTable.clearSelected() 方法中调用可以清空选中
// 使用场景:比如表格既支持批量删除又支持表格内删除,当你勾选☑️了2条数据,
// 但是没通过批量删除按钮删除,而是点击里表格内的操作列删除了一条数据,
// 此时你会发现,再勾选一条数据,明明已经删除一条了,勾选的数组却是三个,
// 这个时候在操作列删除后就需要调用一下此方法了
// 复选框选择的时候触发
selectChange(selectedArr) {
console.log('选中了哪些呢?', selectedArr);
},
// 编辑
edit(row) {
console.log('我要编辑了', row);
},
// 删除
remove(row) {
console.log('我要删除了', row);
},
// 每页多少条
sizeChange(size) {
this.pageValue.pageSize = size;
console.log('现在是一页多少条?', size);
// this.getData();
},
// 翻页
currentChange(page) {
this.pageValue.pageNum = page;
console.log('现在是第几页?', page);
// this.getData();
},
},
二、子组件代码 publicTable.vue
1. html
<div class="table-common">
<el-table
ref="'publicTable'"
border
style="width: 100%"
:data="tableData"
:row-key="rowKey"
@selection-change="handleSelectionChange"
:height="tableHeight"
:header-cell-style="headerCellStyle"
:row-style="rowStyle"
>
<!-- 当数据为空时,如果想添加一个表达时空数据的图片,可以在这里设置,如果没有就不用管了 -->
<template slot="empty">
<span style="display: block; margin: 60px 0"
><img style="width: 60px" src="" />
<!-- 也可以自定义 没有数据时 页面展示的文字 -->
<p style="line-height: 25px; font-size: 13px">暂无数据(自定义哈)</p>
</span>
</template>
<!-- 全选单选 -->
<el-table-column
v-if="configFlag.selection"
align="center"
width="55"
type="selection"
:reserve-selection="config.reserveSelection"
/>
<!-- 序号列 -->
<el-table-column
type="index"
v-if="configFlag.index"
:label="configFlag.indexName || '序号'"
:width="configFlag.indexWidth || 50"
align="center"
:fixed="configFlag.indexFixed || 'left'"
>
<template slot-scope="scope">
<!-- 每页都是从 1 开始 -->
{{ scope.$index + 1 }}
<!-- 第二页从 11 开始 -->
<!-- {{ (pageValue.pageNum - 1) * 10 + (scope.$index + 1) }} -->
</template>
</el-table-column>
<!-- 循环遍历表头展示数据 -->
<el-table-column
v-for="item in columns"
:key="item.fieldIndex"
:width="item.width || ''"
:prop="item.fieldIndex"
:label="item.label"
:align="item.align || 'center'"
:sortable="item.sortable"
:fixed="item.fixed || false"
header-align="center"
:show-overflow-tooltip="item.showOverFlowTooltip"
>
<template slot="header" slot-scope="{ column }">
{{ column.label }}
<el-tooltip
class="item"
effect="dark"
v-if="item.headertip"
:content="item.headertip"
placement="top-start"
>
<i class="el-icon-warning"></i>
</el-tooltip>
</template>
<template slot-scope="scope">
<!-- 枚举值 -->
<div v-if="item.type == 'statMap'">
{{ statMaps(item.options)[scope.row[item.fieldIndex]] || '--' }}
</div>
<!-- 需提示过长信息 -->
<div v-else-if="item.showOverFlowTooltip">
<div class="show-tooltip">{{ scope.row[item.fieldIndex] || '--' }}</div>
</div>
<!-- 保留两位小数 -->
<div v-else-if="item.type == 'tofix2'">
{{
scope.row[item.fieldIndex]
? Number(scope.row[item.fieldIndex]).toFixed(2)
: '--'
}}
</div>
<!-- 金额千分位展示,项目需求,所以暂时就加上了,主要是做个示例,大家可以参考怎么自定义列的一些方法 -->
<div v-else-if="item.type == 'money'">
<span>{{ getMoneyK(scope.row[item.fieldIndex]) || '--' }}</span>
</div>
<!-- 根据需求添加效果 返回的slot可以优化.自己来吧.可以实现操作列等 -->
<slot
v-else-if="item.type == undefined && item.slotname"
:scope="scope"
:name="item.slotname"
/>
<!-- 最普通的情况 -->
<div v-else>
<span>{{ scope.row[item.fieldIndex] || '--' }}</span>
</div>
</template>
</el-table-column>
</el-table>
<el-pagination
v-if="configFlag.needPage"
:total="pageValue.total"
:page-count="pageValue.pageNum"
:page-size="pageValue.pageSize"
:page-sizes="pageSizes"
:current-page.sync="pageValue.pageNum"
layout="prev, pager, next, jumper,total, sizes"
class="fr"
style="margin-top: 12px"
@size-change="sizeChange"
@current-change="currentChange"
@prev-click="prevClick"
@next-click="nextClick"
/>
</div>
2. js部分传参和methods --- (里面所有的默认值根据自己需求更改,或者父组件传参)
export default {
name: 'Table',
data() {
return {};
},
props: {
// 多选保存选中数据
rowKey: {
default: () => row => row.index,
},
// 为表头设计样式
headerCellStyle: {
default: () => {
return { background: '#666', height: '70px', color: 'pink' };
},
},
// 为每一行设计样式,比如设置每行的高度等等
rowStyle: {
default: () => {
return { height: '50px' };
},
},
columns: {
// 表头数据 文案和绑定值,以及需要特殊处理的slot
type: Array,
default: () => [],
},
tableData: {
type: Array, // 后台数据
default: () => [],
},
// 分页参数
pageValue: {
// 分页数据
type: Object,
default: () => {
return {
pageNum: 1,
pageSize: 10,
total: 0,
currentPage: 1, //当前页
};
},
},
// 每页多少条的选项
pageSizes: {
type: Array,
default: () => {
return [10, 20, 50, 100];
},
},
// 表格配置项
configFlag: {
// 配置 其他table配置依次添加
type: Object,
default: () => {
return {
needPage: false, // 是否需要分页
selection: false, // 是否需要多选
index: false, // 是否需要序号
indexWidth: 70, //序号列宽
btn: false, //序号添加自定义html
// 这里不全面,可根据实际情况添加
};
},
},
tableHeight: {
// 可以监听屏幕高度获取。
// 高度
type: Number,
default: () => null,
},
maxHeight: {
// 可以监听屏幕高度获取。
// 高度
type: Number,
default: () => 900,
},
},
computed: {},
methods: {
// 用于表格中字段是枚举值的列 比如性别 0 代表女 1代表男,就不需要对后台数据单独处理了
/**
```
tableconfig:
{
label:‘多选’,
fieldIndex:'selections',
type:'statMap',
options:[{value:'1',label:'男'},{value:'0',label:'女'}]
}
```
*/
statMaps(list) {
if (!list) return;
let obj = {};
list.forEach(item => {
obj[item.value || item.id] = item.label || item.value;
});
return obj;
},
// 金额千位展示:1,234,567,890
getMoneyK(money) {
if (typeof money === 'number') {
money = money.toString();
}
var pattern = /(-?\d+)(\d{3})/;
while (pattern.test(money)) {
money = money.replace(pattern, '$1,$2');
}
return money;
},
// 清空选中
clearSelected() {
// 父组件通过ref调用clearSelected方法,例如 this.$refs.clearTable.clearSelected()
this.$refs.publicTable.clearSelection();
},
/*
默认选中
需要默认选中的在组件中通过this.$refs.publicTable.selected(默认选中的数据:Array)
*/
selected(data) {
if (data.length > 0) {
data.forEach(item => {
this.$refs.publicTable.toggleRowSelection(item, true);
});
}
},
// 设置条数
sizeChange(size) {
this.$emit('sizeChange', size);
},
// 翻页,直接跳转
currentChange(page) {
this.$emit('handleChange', page);
},
//上一页
prevClick(val) {
this.$emit('prevClick', val);
},
//下一页
nextClick(val) {
this.$emit('nextClick', val);
},
// 多选
handleSelectionChange(val) {
this.$emit('handleSelectionChange', val);
},
// 多选
handleSelection(val, row) {
this.$emit('handleSelection', { val, row });
},
handleCellEnter(row, column, cell, event) {
this.$emit('handleCellEnter', { row, column, cell, event });
},
//编辑
handleEdit(index, row, colIndex, field) {
this.$emit('handleEdit', { index, row, colIndex, field });
},
//下拉框事件
onSelected(index, row, field) {
this.$emit('onSelected', { index, row, field });
},
//按钮点击事件
onClickBtn(index, row) {
this.$emit('onClickBtn', { index, row });
},
},
};
3. CSS部分
<style lang="scss" scoped>
.show-tooltip {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
cursor: pointer;
}
</style>
代码部分结束。
总结
可能刚开始上手会不习惯,但用上三四次,尤其是像后台管理系统,表格超多,你会发现,编码会节省很多时间,枚举值也不需要每次对后台返回数据单独处理,封装组件中都有体现。
此版本为V1.0,后续还会更新简化~欢迎持续关注,同时我还封装了一个form表单,但是是基于项目业务封装的,耦合性较差,正在优化中,后续也会给大家分享出来。
gitee地址:日常练习: 没事练习用
封装不易,转载请标明出处...
可以直接复制粘贴(拿来吧你~),有不清晰的地方也请多指教,使用中的问题也可以咨询我哦😊
一键三连还不搞一波?欢迎批评指正