效果图(字段较多,所以分段截图展示):
表格组件public-table.vue
<template>
<div class="public-table">
<!-- 具体使用方法参考public-table-demo.vue -->
<div class="list-table-cont">
<div class="list-table">
<el-table
@selection-change="handleSelectionChange"
:data="tableData"
:stripe="false"
:border="false"
:fit="true"
:show-header="true"
:highlight-current-row="true"
v-loading="columObj.loading"
:row-class-name="tableRowClassName"
class="public-table-cont"
>
<!-- 选择框是否开启,selectable控制是否单行禁用 -->
<el-table-column
v-if="columObj.selection"
type="selection"
:selectable="columObj.selectable"
width="60"
/>
<!-- 普通列 -->
<el-table-column
v-for="(column, columIndex) in columObj.columnData"
:key="columIndex"
:prop="column.prop"
:label="column.label"
:minWidth="column.width"
:fixed="column.fixed"
:align="column.align || 'left'"
:sortable="column.sortable"
:index="columIndex"
show-overflow-tooltip
>
<template slot="header">
{{ column.label }}
<el-popover
v-show="column.isQuestion"
placement="top-start"
title=""
width="200"
trigger="hover"
:content="column.questionCont"
>
<i class="el-icon-question" slot="reference"></i>
</el-popover>
</template>
<template slot-scope="{ row, $index }">
<!-- 默认数据展示,类型为text:true -->
<span
v-if="column.text && column.editRow != $index"
:style="`color:${column.textColor}`"
>
{{ row[column.prop] || '—' }}
</span>
<!-- 对象展示,类型为status:true -->
<span v-if="column.status && row[column.prop]">{{
row[column.prop].msg || '—'
}}</span>
<!-- 自定义内容,数据需要通过自己特殊处理的,类型为slot:true -->
<slot v-if="column.slot" :name="row[column.prop]" :row="row">
<span v-html="column.format(row, $index)"></span>
</slot>
<!-- 自定义格式返回,比如状态,时间拼接等,类型为ownDefined:true-->
<span v-if="column.ownDefined" :style="column.formatColor && column.formatColor(row)">
{{ column.format(row, $index) || '—' }}
</span>
<!--数据有点击事件,可进行点击跳转,弹框等操作,类型为clickable:true -->
<span
v-if="column.clickable"
:class="column.textClass"
@click="column.itemClick(row, $index)"
class="click-style"
>
{{ column.format(row, $index) || '—' }}
</span>
<!-- 返回的数据是简单的数组,类型为isArray:true -->
<span v-if="column.isArray">
<span v-for="(item, index) in row[column.prop]" :key="index">
{{ row[column.prop].length - 1 !== index ? item + ',' : item || '—' }}
</span>
</span>
<!-- 既有默认的返回数据,又有自定义的可点击内容,类型为textClick:true -->
<span v-if="column.textClick">
<span>{{ row[column.prop] || '—' }}</span>
<span class="blue-line">|</span
><span
class="click-style"
@click="column.itemClick(row, $index)"
:class="column.textClass"
>{{ column.textCont || '—' }}</span
>
</span>
<!-- switch开关,打开时值为true ,关闭时值为false -->
<el-switch
v-if="column.switch"
v-model="row[column.prop]"
:inactive-text="row[column.prop] ? column.openText : column.closeText"
@change="switchChange(row, $index)"
/>
<!-- switch开关,打开时值为1 ,关闭时值为0 -->
<el-switch
v-if="column.switchNum"
:active-value="1"
:inactive-value="0"
v-model="row[column.prop]"
:inactive-text="row[column.prop] ? column.openText : column.closeText"
@change="switchChange(row, $index)"
/>
<!-- 单个图片展示,类型为image:true -->
<div class="logo-box flex-column-center-center" v-if="column.image">
<el-image
class="logo"
:class="column.imgStyle"
:src="row[column.prop]"
:preview-src-list="[row[column.prop]]"
alt="图片"
/>
</div>
<!-- 图片数组 -->
<div class="logo-box flex-column-center-center" v-if="column.imageArr">
<el-image
class="logo"
:class="column.imgStyle"
v-if="row[column.prop].length > 0"
:src="row[column.prop][0]"
:preview-src-list="row[column.prop]"
alt="图片"
/>
</div>
<!-- 操作按钮 -->
<span
v-show="column.isOperation"
v-for="(operations, index) in column.operation"
:key="index"
>
<el-button
:icon="operations.icon"
:type="operations.type"
@click="operations.buttonClick(row, $index)"
:class="
operations.format && operations.format(row)
? operations.disabledClass
: operations.styleClass
"
:disabled="operations.format && operations.format(row)"
size="small"
>{{ operations.label }}</el-button
>
<span v-show="operations.dividerLine" class="divider-line">|</span>
</span>
</template>
</el-table-column>
<!-- 自定义操作栏,与isOperation不能同时存在-->
<slot name="tableOperations"></slot>
<!-- 暂无数据 -->
<div slot="empty" class="empty">
<img :src="`${ASSET_HOST}/event/activity_null.png`" />
<span>暂无数据</span>
</div>
</el-table>
</div>
<!-- 分页 -->
<!-- noPagination为true时不显示分页,默认为false,可不传此参数 -->
<div class="pagination-panel flex-end" v-show="!columObj.noPagination">
<div class="total-pages">
共
<span>{{ pageObj.total }}</span> 条数据
</div>
<div class="total-pages" :style="{ textAlign: pageObj.position || 'center' }">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageObj.page"
:page-size="pageObj.pageSize"
layout="sizes, prev, pager, next,jumper"
:total="pageObj.total"
>
</el-pagination>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'public-table', //共用table组件
directives: {
// 自定义指令,用于可编辑input自动获取焦点
focus: {
inserted: function (e) {
e.querySelector('input').focus();
},
},
},
props: {
tableData: {
type: Array,
required: true,
},
columObj: {
type: Object,
required: true,
},
//columObj.type(如果为""空,就不会加载多选框,或者index编号),lazy(是否支持懒加载)
//columnData.columType(列类型,可选text(默认为普通文字模式),input(input可编辑框),switch(switch开关),image(图片),operation(操作按钮))
//prop(参数),label(列名),width(宽度),align(对齐方式),sortable(是否支持排序)
//如果为操作列,则需要填写需要的操作按钮,类型为Object。type(按钮样式,参考el—botton类型),label(按钮文字)icon(参考el-icon),color(字体颜色),buttonClick为点击后调用的方法名称
pageObj: {
type: Object,
required: true,
},
},
methods: {
// switchChange调用
switchChange(row, $index, prop) {
this.$emit('switchChange', row, $index, prop);
},
// 帮助点击行,获取点击的下标
tableRowClassName({ row, rowIndex }) {
row.rowIndex = rowIndex;
},
// 选择的数据
handleSelectionChange(val) {
this.$emit("handleSelectionChange", val);
},
// 条数变化
handleSizeChange(e) {
this.$emit('handleSizeChange', e);
},
// 页码变化
handleCurrentChange(e) {
this.$emit('handleCurrentChange', e);
},
},
};
</script>
<style lang='scss' scoped>
.public-table {
.el-button {
margin: 0 6px;
}
.text-underline {
text-decoration: underline;
}
.click-style {
cursor: pointer;
}
.text-color {
color: #0064ff;
}
.red-text {
color: red !important;
}
.blue-text {
color: rgba(0, 100, 255, 1) !important;
}
.disabled-text {
color: #999 !important;
}
/deep/ .el-input__inner {
border: none;
}
/deep/ .el-image__inner {
height: 50px;
}
// switch左边文字颜色
/deep/ .el-switch__label--left {
color: #606266;
}
.flex-column-center-center {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo-box {
width: 50px;
height: 50px;
/deep/.el-image__inner {
height: auto !important;
}
.logo {
width: 50px;
height: 50px;
display: inline-block;
object-fit: cover;
}
.logo-style {
height: 40px !important;
}
.logo-list-style {
width: 80px !important;
height: 80px !important;
}
}
}
</style>
public-table-demo.vue页面引用组件
<template>
<div class="public-table-demo">
<div class="public-table-demo-titles flex-between">
<div class="public-table-demo-titles-left">封装表格使用示例</div>
</div>
<div class="public-table-demo-cont">
<!-- 表格(直接复制这个组件到对应文件) -->
<public-table
:tableData="tableData"
:columObj="columObj"
:pageObj="pageObj"
@switchChange="switchChange"
@handleSelectionChange="handleSelectionChange"
@handleSizeChange="handleSizeChange"
@handleCurrentChange="handleCurrentChange"
>
<!-- 放开注释代码并删除columnData中的isOperation为true的操作列则为自定义操作栏 -->
<!-- <div slot="tableOperations">
<el-table-column prop="status" width="200" fixed="right" label="操作">
<template slot-scope="scope">
<el-button
type="text"
size="small"
@click.native="editBanner(scope.row)"
>编辑</el-button
>
</template>
</el-table-column>
</div> -->
</public-table>
</div>
</div>
</template>
<script>
export default {
name: 'public-table-demo',
components: {
publicTable: () => import('@/components/common/public-table.vue'),
},
data() {
return {
tableData: [
{
cont: '普通数据',
setColor: '设置为蓝色',
isQuestion: '标题带问号',
logo: 'https://tuoluohuodong.oss-cn-shang hai.aliyuncs.com/digital_system/tuoluoicon.png',
logoList: [
'https://tuoluohuodong.oss-cn-shang hai.aliyuncs.com/digital_system/30841d9826d04081961102138d606ac3.jpeg',
'https://tuoluohuodong.oss-cn-shang hai.aliyuncs.com/digital_system/8e696633c92249ce806d417c26c630f5.jpeg',
],
isOpenSwitch: true,
isOpenSwitchNum: 0,
status: 1,
startTime: '2022-03-31 00:00:00',
endTime: '2023-03-31 00:00:00',
sex: 1,
booth: null,
exhibition: null,
clickValue: '可点击跳转',
productInfoVOList: [
{ id: '3523435726235345363', productSn: '419225611403', auditStatus: 1 },
{ id: '3523435726235345364', productSn: '673929573648', auditStatus: 2 },
],
venueVal: ['B', 'C', 'C'],
numDetail: 99,
objmsg: {
msg: '对象啊',
},
},
{
cont: '普通数据',
setColor: '设置为蓝色',
isQuestion: '标题带问号',
logo: 'https://tuoluohuodong.oss-cn-shang hai.aliyuncs.com/digital_system/tuoluoicon.png',
logoList: [
'https://tuoluohuodong.oss-cn-shang hai.aliyuncs.com/digital_system/d49e5941cc834a28ad0b3cd730bf01ea.jpg',
'https://tuoluohuodong.oss-cn-shang hai.aliyuncs.com/digital_system/b03a4a6605f540ae9148c008a7bc8193.jpg',
],
isOpenSwitch: false,
isOpenSwitchNum: 1,
status: 2,
startTime: '2022-03-01 12:00:00',
endTime: '2023-03-01 18:00:00',
sex: 2,
booth: '展馆号',
exhibition: '展位号',
clickValue: '可点击跳转',
productInfoVOList: [
{ id: '3578388750457094201', productSn: '019109210492', auditStatus: -1 },
],
venueVal: ['A', 'C', 'D'],
numDetail: 10,
objmsg: {
msg: '对象啊',
},
},
], //列表数据
columObj: {
selection: true, // 是否显示选择框
// noPagination:true,//是否显示分页(为true不显示,默认显示分页则不需要此参数)
/***
* column列,
* columType(列类型,可选text(默认为普通文字模式),
* switch(switch开关,后台返回false或true),
* switchNum(switch开关,后台返回0或1),
* image(图片),
* operation(操作按钮)
* textColor(文本颜色,不传则是默认颜色)
* ownDefined(自定义返回内容)
* clickable(内容可点击操作)
* isArray(数组)
* textClick(又有普通内容又有可点击操作内容)
***/
/***
* prop(参数),
* label(列名),
* width(宽度),
* align(对齐方式,默认左对齐),
* sortable(是否支持排序)
* format(自定义值)
* formatColor(自定义值的颜色,需要则设置)
* textClass(样式设置)
* itemClick(内容点击事件)
* textCont(有点击事件的固定内容)
***/
columnData: [
{
text: true,
prop: 'cont',
label: '默认',
width: '150',
},
{
text: true,
textColor: '#0064ff',
prop: 'setColor',
label: '设置颜色',
width: '150',
},
{
text: true,
prop: 'isQuestion',
label: '显示问号',
width: '120',
isQuestion: true, //是否显示问号tips
questionCont: '提示内容啊啊', //问号显示的内容
},
{
image: true,
prop: 'logo',
label: 'logo展示',
width: '120',
imgStyle: 'logo-style',
},
{
imageArr: true,
prop: 'logoList',
label: '多张图',
width: '120',
imgStyle: 'logo-list-style',
},
{
switch: true,
prop: 'isOpenSwitch',
label: 'switch按钮(后台返回false或true)',
width: '300',
},
{
switchNum: true,
prop: 'isOpenSwitchNum',
label: 'switch按钮(后台返回0或1)',
width: '260',
},
{
ownDefined: true,
prop: 'status',
label: '状态(自定义颜色)',
width: '180',
format: (row) => {
let text = '';
switch (row.status) {
case 1:
text = '绿色';
break;
case 2:
text = '黄色';
break;
default:
return '—';
}
return text;
},
formatColor: (row) => {
switch (row.status) {
case 1: {
return { color: '#04b935' };
}
case 2: {
return { color: '#ffab4f' };
}
default: {
return { color: '#ee423d' };
}
}
},
},
{
slot: true,
prop: 'productInfoVOList',
label: '数组',
width: '300',
format: (row) => {
const { productInfoVOList } = row;
const auditStatus = { '-1': '报名失败', 1: '报名成功', 2: '审核中' };
let rowEl = productInfoVOList.map((item) => {
return `<div> ${item.productSn}(${auditStatus[item.auditStatus]})</div>`;
});
let rowElVal = rowEl.toString();
return rowElVal.replace(/,/g, ''); //去掉逗号
},
},
{
ownDefined: true,
prop: 'startTime',
label: '时间拼接',
width: '380',
format: (row) => {
return row.startTime + '~' + row.endTime;
},
},
{
ownDefined: true,
prop: 'sex',
label: '性别(后台返回1和2)',
width: '200',
format: (row) => {
let text = '';
switch (row.sex) {
case 1:
text = '男';
break;
case 2:
text = '女';
break;
default:
text = '—';
}
return text;
},
},
{
clickable: true,
prop: 'startTime',
itemClick: this.addBooth,
label: '两个字段且带点击事件',
width: '200',
textClass: 'text-underline',
format: (row) => {
return row.exhibition || row.booth
? `${row.exhibition || '暂无'} | ${row.booth || '暂无'}`
: '点击设置展位';
},
},
{
clickable: true,
prop: 'clickValue',
itemClick: this.goUrl,
textClass: 'text-color',
label: '带点击事件',
width: '140',
format: (row) => {
return row.clickValue;
},
},
{
isArray: true,
prop: 'venueVal',
label: '数组',
width: '140',
},
{
textClick: true,
prop: 'numDetail',
itemClick: this.goPage,
textClass: 'text-color',
textCont: '点击的文案',
label: '内容与点击事件',
width: '180',
},
{
status: true,
prop: 'objmsg',
label: 'obj类型',
width: '140',
},
/***
* 如果为操作列,则需要填写需要的操作按钮,类型为Object。
* type(按钮样式,参考el—botton类型),
* label(按钮文字)
* icon(参考el-icon),
* color(字体颜色),
* isShow(是否显示按钮),
* dividerLine(是否显示分隔线)
* styleClass(按钮样式,不传则为默认)
***/
{
fixed: 'right',
isOperation: true,
label: '操作',
width: '140',
operation: [
{
type: 'text',
label: '编辑',
icon: '',
buttonClick: this.editTable,
disabledClass: 'disabled-text ',
dividerLine: true,
format:(row) => {
return row.sex==1
},//禁用条件
},
{
type: 'text',
label: '删除',
icon: '',
styleClass: 'red-text',
buttonClick: this.delTable,
},
],
},
],
},
pageObj: {
total: 0,
page: 1,
pageSize: 10,
}, //分页对象
};
},
methods: {
// 设置占位
addBooth(row, $index) {
console.log(row, '设置');
},
// 跳转链接
goUrl(row, $index) {
console.log(row, '点击跳转');
},
// 跳转详情
goPage(row, $index) {
console.log(row, '跳转详情');
},
// 编辑事件
editTable(row, $index) {
console.log(row, $index, '编辑');
},
// 删除事件
delTable(row, $index) {
console.log(row, $index, '删除');
},
// 行改变事件
rowOperation(row, $index) {
console.log(row, $index);
},
// cahnge改变事件
switchChange(row, $index) {
console.log(row, $index, 'switch');
},
// 选中的条数
handleSelectionChange(val) {
console.log(val, "选中的数据");
},
// 获取数据的方法
getData() {},
// 改变页数
handleCurrentChange(val) {
this.pageObj.page = val;
this.getData();
},
// 改变页码
handleSizeChange(val) {
this.pageObj.pageSize = val;
this.getData();
},
},
};
</script>
<style lang='scss' scoped>
.public-table-demo {
background: #ffffff;
padding: 0.32rem 0.2rem 0.16rem 0.2rem;
// border: 1px solid #dcdfe6;
border-radius: 4px;
.public-table-demo-titles-left {
font-size: 24px;
font-weight: bold;
}
}
</style>