Vue 项目实战:全局封装 Element UI 表格组件
在维护中大型后台管理系统时,我们常遇到表格配置重复、样式不统一的问题。与其在每个页面重复编写 el-table 的模板和逻辑,不如将其二次封装为一个全局组件。这样既能保证交互体验的一致性,又能大幅减少样板代码。
核心思路
我们将封装一个名为 NewTable 的组件,它接收 tableOption 作为配置项,内部根据配置动态生成列结构。利用 Vue 2 的 $attrs 透传机制,可以将原生 el-table 的属性直接传递给底层组件,实现高度灵活的控制。
组件实现
首先创建 new-table/index.vue 文件。这里重点处理了表头渲染逻辑,支持索引、多选以及自定义插槽渲染。
<template>
<div class="new_table">
<div class="table_main">
<el-table
ref="table"
:data="tableDataList"
:span-method="objectSpanMethod"
:highlight-current-row="true"
v-bind="$attrs"
border
@selection-change="selectionChange"
v-loading="tableLoading"
style="width: 100%"
>
<template v-for="(col, index) in tableOption.columns">
<!-- 序号列 -->
<template v-if="col.type == 'index'">
<el-table-column
type="index"
:key="index"
:label="col.label || '编号'"
:width="col.width || 50"
align="center"
></el-table-column>
</template>
<!-- 选择列 -->
<template v-if="col.type == 'selection'">
<el-table-column
type="selection"
:key="index"
:width="col.width || 50"
align="center"
></el-table-column>
</template>
<!-- 文本列及自定义渲染 -->
<template v-if="col.type == 'text'">
<template v-if="col.render">
<el-table-column
:key="index"
:show-overflow-tooltip="!!col.overflow"
:align="col.align || 'left'"
:sortable="!!col.sortable"
:prop="col.prop"
:label="col.label"
:width="col.width || ''"
>
<template slot-scope="scope">
<table-render
:render="col.render"
:scope="scope"
:prop="col.prop"
></table-render>
</template>
</el-table-column>
</template>
<template v-else>
<el-table-column
:key="index"
:show-overflow-tooltip="!!col.overflow"
:align="col.align || 'left'"
:sortable="!!col.sortable"
:prop="col.prop"
:label="col.label"
:width="col.width || ''"
></el-table-column>
</template>
</template>
</template>
</el-table>
</div>
</div>
</template>
<script>
export default {
name: 'NewTable',
props: {
tableDataList: {
type: Array,
required: true
},
tableOption: {
type: Object,
default: () => ({})
},
tableLoading: {
type: Boolean,
default: false
}
},
methods: {
// 合并行策略示例
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (rowIndex % 2 === 0) {
return { rowspan: 2, colspan: 1 };
}
return { rowspan: 0, colspan: 0 };
},
// 选中事件处理
selectionChange(val) {
this.$emit('selection-change', val);
}
}
};
</script>
<style scoped>
.new_table {
padding: 10px;
}
.table_main {
background: #fff;
border-radius: 4px;
}
</style>

