1. 二次封装table, 新建一个 OnlyTable.vue
其中的 v-scroll-bar-fixed 指令是横向滚动条固定
<template>
<div class="table">
<el-table
ref="table"
:data="data"
v-bind="tableProps"
v-on="tableEvent"
:border="border"
:toolbar="toolbar"
:toolbar-grey="true"
v-el-loading="loading"
:header-fixed-props="headerFix && headerFixProps"
cell-empty-text="-"
:cell-style="cellStyle"
:cell-class-name="cellClassName"
:summary-method="summaryMethod"
:show-summary="showSummary"
:summaryGrey="showSummary"
v-scroll-bar-fixed>
<template #tools>
<div>
<slot name="tools" />
</div>
</template>
<el-table-column type="selection" v-if="isSelection"></el-table-column>
<el-table-column type="radio" v-if="isRadioSelectable"></el-table-column>
<el-table-column
v-if="isIndex"
type="index"
:index="indexMethod"
label="序号"
width="60"
fixed />
<template v-for="(item, index) in column">
<el-table-column
v-if="$scopedSlots[item.value]"
:key="index"
:label="item.label"
:prop="item.value"
v-bind="item.props">
<template #header="{ column }" v-if="item.props?.required">
<span class="el-form-item__required">*</span>
{{ column.label }}
</template>
<template #default="{ row, $index }">
<slot :name="item.value" :row="row" :index="$index"></slot>
</template>
</el-table-column>
<el-table-column
v-else
:key="`key-${index}`"
:label="item.label"
:prop="item.value"
v-bind="item.props">
<template #header="{ column }" v-if="item.props?.required">
<span class="el-form-item__required">*</span>
{{ column.label }}
</template>
</el-table-column>
</template>
</el-table>
<div slot="tableFooter">
<slot name="tableFooter" />
</div>
<div v-if="needPage" class="page">
<div class="page-total">
<span>Total {{ total }} items </span>
</div>
<el-pagination
:current.sync="page.pageNum"
:pageSize.sync="page.pageSize"
:page-size-options="[10, 20, 50, 100, 300, 500]"
:total="total"
showTotalPages
showSizeChanger
showQuickJumper
@current-change="pageChange"
@size-change="sizeChange">
</el-pagination>
</div>
</div>
</template>
<script>
export default {
name: 'OnlyTable',
components: {},
props: {
// 表格表头信息
column: {
type: Array,
default: () => [],
},
data: {
type: Array,
default: () => [],
},
tableProps: {
type: Object,
default: () => ({}),
},
tableEvent: {
type: Object,
default: () => ({}),
},
cellStyle: {
default:() => {},
},
cellClassName: {
default: () => {},
},
loading: {
type: Boolean,
default: false,
},
// 是否需要分页
needPage: {
type: Boolean,
default: true,
},
total: {
type: Number,
default: 0,
},
size: {
type: Number,
default: 10,
},
isIndex: {
type: Boolean,
default: false,
},
// 是否多选
isSelection: {
type: Boolean,
default: false,
},
// 是否支持单选
isRadioSelectable: {
type: Boolean,
default: false,
},
headerFix: {
type: Boolean,
default: true,
},
border: {
type: Boolean,
default: false,
},
// 是否显示工具栏
toolbar: {
type: Boolean,
default: false,
},
page: {
type: Object,
default: () => ({}),
},
// 统计方法
summaryMethod: {
default:() => {},
},
// 是否显示统计
showSummary: {
type: Boolean,
default: false,
},
fixContainerEl: {
type: String,
default: '.main-container-wrap'
}
},
data() {
return {
// current: 1,
// pageSize: this.size || 50,
// 表头信息是否固定
headerFixProps: {
container: () => document.querySelector(this.fixContainerEl),
zIndex: 10,
},
};
},
mounted() {},
methods: {
indexMethod(index) {
return index;
},
getTableRef() {
return this.$refs.table;
},
reset() {
this.current = 1;
},
pageChange(current) {
this.$emit('pageChange', {
page: current,
size: this.pageSize,
});
},
sizeChange(pageSize) {
this.$emit('pageChange', {
page: 1,
size: pageSize,
});
},
},
};
</script>
<style lang="less" scoped>
:deep(.el-table .cell) {
height: auto;
}
.page {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
overflow: hidden;
margin-top: 20px;
&-total {
font-size: 14px;
color: #8b8b8b;
}
}
</style>
2. 引用 组件
<template>
<OnlyTable
ref="tableRef"
v-bind="tableProps"
@pageChange="onPageChange"
:page="page"
:cellStyle="cellStyle"
:cellClassName="cellClassName"
>
<template #count="{ row }">
{{row.count }}
</template>
<template #opts="{ row }">
<el-button type="link" @click="goDetail(row)" > 详情 </el-button>
</template>
</OnlyTable>
</template>
<script>
import OnlyTable from '@/components/OnlyTable/index.vue';
import lodash from 'lodash';
export default {
components: {
OnlyTable
},
data() {
const tableProps = {
column: [
{
value: '',
label: '多选',
props: {
width: 60,
fixed: 'left',
type: 'selection',
reserveSelection: true,
selectable: (row) => {
// 根据条件判断是否可以
return row.status === '1';
}
},
},
{value: 'count',label: '数量',props: {width: 130,fixed: 'left',}},
{value: 'opts',label: '操作',props: {width: 60,fixed: 'right', }}
],
data: [],
total: 0,
loading: false,
toolbar: true,
tableEvent: {
select: this.tableSelect,
'select-all': this.tableSelect,
// 统计显示
summaryMethod: this.getSummaries,
},
};
return {
tableProps,
page: {
pageNum: 1,
pageSize: 50,
},
tableSelectedData: []
};
},
methods: {
// 列表分页
onPageChange(data) {
this.page.pageNum = data.page || this.page.pageNum;
this.page.pageSize = data.size || this.page.pageSize;
this.query();
},
tableSelect(selection) {
if (selection.length <= 500) {
this.tableSelectedData = lodash.cloneDeep(selection);
} else {
const tableRef = this.$refs.tableRef.getTableRef();
tableRef.clearSelectionCache();
tableRef.toggleBatchSelectionCache(this.tableSelectedData, true, true);
this.$message.warning('最多选择500条')
}
},
// 行样式
cellStyle({ row }) {
if (['合计'].includes(row.seriesName) ) {
return {
background: 'rgb(245 246 247)',
color: '#f76400'
};
}
if (['小计'].includes(row.seriesName) ) {
return {
background: 'rgb(245 246 247)',
};
}
},
// 行样式类名
cellClassName({row}) {
if (['合计'].includes(row.seriesName)) {
return 'special-cell';
}
},
// 统计
getSummaries({ column, data }) {
let res = [];
column.map((col, i) => {
let addRes = 0;
data.map(item => {
addRes += Number(item[col.prop]);
});
if (i) {
let content = '';
if (!isNaN(addRes)) {
content = addRes;
if (col.prop === 'price') content = addRes.toFixed(2);
}
res.push(content);
} else {
res.push('总计');
}
});
return res;
}
},
};
</script>