前提
写这个目的是纯粹记录一下,自己项目中使用到的关于el-table组件二次封装的一些细节。
common-table-list公共组件使用方法
<common-table-list :data="tableData" :pagination="pagination" :total="total" :tableColumnProps="tableColumnProps"
@handlePageChange="handlePageChange" ref="commonTableList">
<template slot="code" slot-scope="scope">
xxxx
</template>
</common-table-list>
// data
tableColumnProps: {
showSelection: false,
selectionConfig: {
width: 0,
reserveSelection: false
},
showIndex: false,
data: [
{label: 'xxxx',prop: 'code',showSlot: true},
],
},
total: 0,
pagination: {
pageSize: 10,
pageNum: 1,
},
// methods
handlePageChange(obj){
this.pagination.pageNum = obj.pageNum;
this.pagination.pageSize = obj.pageSize;
// 接下来分页获取数据
},
源码分析
el-table部分
- template
使用$attrs和$listeners保证该组件能够具备el-table的所有功能
<el-table
class="common-el-table"
ref="tableList"
v-loading="loading"
v-bind="{...$attrs,...bindProps}"
:data="tableData"
tooltip-effect="light"
height="100%"
v-on="onTableListeners"
@selection-change="handleSelectionChange"
@sort-change="tableSortChange">
</el-table>
props: {
data: Array,
rowKey: String,
loading: {
type: Boolean,
default: false
},
},
data(){
return {
selfEmit: Object.freeze({ // common-table-list组件自身定义的事件,防止重复传递给el-table
'handlePageChange': 'handlePageChange',
'filter-change': 'filter-change',
'clickIcon': 'clickIcon',
'sort-change': 'sort-change',
'selection-change': 'selection-change'
}),
}
},
computed: {
// table v-bind
bindProps() {
const target = {};
if(this.rowKey){
target['row-key'] = this.getRowKeys;
}
return target;
},
// listeners common-table-list组件自身定义的事件,防止重复传递给el-table
onTableListeners(){
const listeners = deepClone(this.$listeners);
const selfEmit = this.selfEmit;
Object.keys(selfEmit).forEach((key) => {
if(listeners.hasOwnProperty(key)) delete listeners[key];
});
return listeners;
},
tableData:{
get () {
return deepClone(this.data || [])
},
set (value) {
return value;
}
}
},
methods: {
// 获取row的key值
getRowKeys(row) {
return row[this.rowKey];
},
handleSelectionChange(val){
this.multipleSelection = val;
this.$emit('selection-change',val);
},
/**
* @description: 监听order变化时触发
* custom时默认排序方法失效,需自定义
* @param {*}
* @return {*}
*/
tableSortChange({ prop, order, column }) {
this.pagination.pageNum = 1;
// 自定义过滤
this.$emit('sort-change',{ prop, order, column })
},
}
el-table-column部分
/**
* @description: 处理columnData数据v-bind
* @param {*} source
* @param {*} filterKeys 需要过滤的数据
* @param {*} target
* @return {*}
*/
const handleColumnData = (source,filterKeys,target) => {
Object.keys(source).forEach((key) => {
if(source.hasOwnProperty(key) && !filterKeys.includes(key)) target[key] = source[key];
})
return target;
}
// tableColumnProps是props传入的值;defaultColumnTableProps 是默认值
// merge 之后传递的值可以不用写,直接取默认值
tableColumnPropsComputed(){
return merge(deepClone(defaultColumnTableProps),this.tableColumnProps);
},
// props
tableColumnProps: {
type: Object,
default(){
return deepClone(defaultColumnTableProps)
}
},
实现selection部分
<el-table-column
type="selection"
v-bind="bindSelectionProps"
:width="tableColumnPropsComputed.selectionConfig.width"
v-if="tableColumnPropsComputed.showSelection"></el-table-column>
// computed
// table-column selection v-bind
bindSelectionProps(){
return this.tableColumnPropsComputed.selectionConfig
},
实现index部分
<el-table-column label="序号" type="index" show-overflow-tooltip v-if="tableColumnPropsComputed.showIndex"></el-table-column>
实现其它column部分
<template v-for="(columnData,columnIndex) in tableColumnPropsComputed.data">
<el-table-column v-if="columnData.show && columnData.showColumn" :key="columnIndex" :label-class-name="getCoumnLabelClassName(columnData)"
:show-overflow-tooltip="columnData.showTooltip === void 0 || columnData.showTooltip" v-bind="bindColumnProps(columnData)" :column-key="getKey()">
<template slot-scope="scope">
<slot :name="columnData.prop" :row="scope.row" :column="scope.column" :columnData="columnData" :$index="scope.$index" v-if="columnData.showSlot"></slot>
<span v-else>{{formateTableData(scope,columnData)}}</span>
</template>
</el-table-column>
</template>
// computed
// table-column v-bind
bindColumnProps(){
return function(columnData){
const target = {};
const filterKeys = ['show','showColumn','showColumnHidden','sortable','filterable','filterConfig','showTooltip'];
return handleColumnData(columnData,filterKeys,target);
}
},
// methods
/**
* @description: 判断是否是函数
* @param {*}
* @return {*}
*/
isFunction(obj){
return typeof obj === 'function' && typeof obj.nodeType !== 'number';
},
/**
* @description: 格式化数据
* @param {*}
* @return {*}
*/
formateTableData(scope,columnData){
if(columnData.formate && this.isFunction(columnData.formate)) return columnData.formate(scope,columnData);
if(columnData.formatter && this.isFunction(columnData.formatter)) return columnData.formatter(scope.row, scope.column, scope.row[scope.column.property], scope.$index);
return scope.row[columnData.prop];
},
el-pagination部分
<!-- 分页 -->
<div class="el-pagination-wrapper" v-show="tableData.length && total">
<el-pagination background @current-change="handleCurrentChange" @size-change="handleSizeChange"
:current-page="pagination.pageNum" :page-size="pagination.pageSize" :page-sizes="pageSizes"
layout="sizes,prev, pager, next,total" :total="total">
</el-pagination>
</div>
// props
pagination: {
type: Object,
default(){
return {
pageNum: 1,
pageSize: 10
}
}
},
total: Number,
pageChangeTrigger: String,
pageSizes: {
type: Array,
default(){
return [10, 20, 50, 100, 500]
}
},
// methods
/**
* @description: 分页
* @param {*}
* @return {*}
*/
handlePageChange(){
const obj = {
pageNum: this.pagination.pageNum,
pageSize: this.pagination.pageSize
}
this.$emit('handlePageChange',obj);
if(this.pageChangeTrigger) this.$parent[this.pageChangeTrigger](obj);
},
handleCurrentChange(val) {
this.pagination.pageNum = val;
this.handlePageChange();
},
handleSizeChange(val) {
this.pagination.pageNum = 1;
this.pagination.pageSize = val;
this.handlePageChange();
},
/**
* @description: 将页码前置一页(用于数据删除时,数据已经是分页最后一条时)
* @param {*}
* @return {*}
*/
handleDeletePageNum(){
const isNeedcPrev = this.tableData.length === 1 || this.multipleSelection.length === this.tableData.length;
if(isNeedcPrev) this.pagination.pageNum = this.pagination.pageNum === 1 ? 1 : this.pagination.pageNum - 1;
this.handlePageChange();
},
其它功能---基于项目自己实现的功能
该组件还实现了以下功能
- 自定义排序功能
- 操作区el-table-column部分
- empty部分
<slot name="empty" slot="empty"></slot>
- footer部分
<slot name="footer"></slot>
仓库地址
放在这里,有问题欢迎提出改进