引言
在后台管理系统中,表格是最常用的数据展示方式之一。不同的用户或不同的场景下,我们往往需要展示不同的表格列,或者对列的显示方式有不同的需求。本文将介绍如何基于 Vue 3 和 Element Plus 实现一个可定制的动态表格列配置组件,让用户可以自由选择需要显示的列、调整列的顺序、配置列的显示方式等。
组件设计思路
我们的动态表格列配置组件主要由三部分组成:
- CustomizeTableColumns - 负责单个表格列的渲染
- ColumnConfigDialog - 提供列配置的交互界面
- 主页面 - 整合组件并提供数据
这种设计遵循了单一职责原则,每个组件只关注自己的核心功能,使得代码更加清晰、易于维护。
核心组件实现
1. CustomizeTableColumns 组件
xml
<template>
<el-table-column
:prop="column.prop"
:label="column.label"
:align="column.align || 'center'"
:width="column.width"
:min-width="column.minWidth"
:fixed="column.fixed"
:sortable="column.sortable"
:formatter="column.formatter ? dateFormatter : null"
show-overflow-tooltip
>
<!-- 自定义列模板 针对特殊列通过插槽进行特殊处理 -->
<template #default="scope" v-if="column.slot">
<slot name="column-cell" :column="column" :row="scope.row" :index="scope.$index"></slot>
</template>
</el-table-column>
</template>
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
const props = defineProps({
column: {
type: Object,
required: true
}
})
</script>
功能说明:
- 封装了
el-table-column
的基本配置 - 通过
slot
支持自定义列内容渲染 - 内置了日期格式化功能
使用示例:
xml
<CustomizeTableColumns v-for="col in dynamicColumns" :key="col.prop" :column="col">
<template #column-cell="{ column, row, index }">
<!-- 自定义列内容 -->
<template v-if="column.prop === 'index'">
{{ index + (queryParams.pageNo - 1) * queryParams.pageSize + 1 }}
</template>
<template v-else-if="column.prop === 'typeName'">
<span
style="cursor: pointer; color: #409eff"
v-if="row.id"
@click="openForm('preview', row.customerName, row.customerId, row.id)"
>
{{ row.typeName }}
</span>
</template>
</template>
</CustomizeTableColumns>
2. ColumnConfigDialog 组件
xml
<template>
<el-dialog
v-model="showDialog"
title="表格列配置"
width="800px"
append-to-body
class="column-config-dialog"
>
<!-- 对话框内容 -->
</el-dialog>
</template>
<script setup lang="ts">
import draggable from 'vuedraggable'
const props = defineProps({
modelValue: Boolean,
columns: Array,
defaultColumns: Array
})
const emit = defineEmits(['update:modelValue', 'update:columns'])
// 控制对话框显示
const showDialog = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value)
})
// 临时列配置
const tempColumns = ref([])
// 全选控制
const checkAll = computed({
get: () => tempColumns.value.every(col => col.visible),
set: (val) => tempColumns.value.forEach(col => col.visible = val)
})
// 保存配置
const saveColumnConfig = () => {
const newColumns = tempColumns.value.map((col, index) => ({
...col,
order: col.fixed ? col.order : index
}))
emit('update:columns', newColumns)
showDialog.value = false
}
</script>
功能特点:
- 列可见性控制:可以勾选显示/隐藏列
- 拖拽排序 :使用
vuedraggable
实现列顺序调整 - 基础配置:可以修改列名、对齐方式、宽度等
- 高级配置:支持固定列、最小宽度、排序等高级设置
- 全选/重置:一键全选或重置为默认配置
3. 主页面集成
php
<template>
<!-- 表格部分 -->
<el-table :data="list">
<CustomizeTableColumns v-for="col in dynamicColumns" :key="col.prop" :column="col">
<!-- 自定义列模板 -->
</CustomizeTableColumns>
</el-table>
<!-- 配置对话框 -->
<ColumnConfigDialog
v-model="showColumnConfig"
:columns="columnOptions"
:default-columns="defaultColumns"
@update:columns="handleColumnsUpdate"
/>
</template>
<script setup lang="ts">
// 默认列配置
const defaultColumns = ref([])
// 当前列配置
const columnOptions = ref([
{
prop: 'index',
label: '序号',
width: 80,
fixed: 'left',
align: 'center',
slot: true,
visible: true,
order: 0
},
{
prop: 'customerName',
label: '客户名称',
width: 150,
align: 'center',
visible: true,
order: 1
},
{
prop: 'typeName',
label: '任务名称',
align: 'center',
slot: true,
visible: true,
sortable: false,
showAdvanced: true,
minWidth: 80,
order: 2
},
{
prop: 'publishUserName',
label: '发布人',
width: 150,
align: 'center',
visible: true,
sortable: false,
showAdvanced: true,
order: 3
},
{
prop: 'receiveUserName',
label: '接收人',
width: 150,
align: 'center',
visible: true,
sortable: false,
showAdvanced: false,
order: 4
},
{
prop: 'missionStatus',
label: '状态',
width: 150,
align: 'center',
slot: true,
visible: true,
sortable: false,
showAdvanced: false,
order: 5
},
{
prop: 'missionCancelReasonName',
label: '作废原因',
width: 150,
align: 'center',
visible: true,
sortable: false,
showAdvanced: false,
order: 6
},
{
prop: 'missionRejectReasonName',
label: '拒绝原因',
width: 150,
align: 'center',
visible: true,
sortable: false,
showAdvanced: false,
order: 7
},
{
prop: 'missionRejectReasonDesc',
label: '拒绝描述',
width: 150,
align: 'center',
visible: true,
sortable: false,
showAdvanced: false,
order: 8
},
{
prop: 'publishTime',
label: '发布时间',
minWidth: 180,
align: 'center',
sortable: false,
showAdvanced: false,
formatter: true,
visible: true,
order: 9
},
{
prop: 'operation',
label: '操作',
visible: true,
minWidth: 140,
fixed: 'right',
slot: true
}
])
// 动态列(根据配置生成的可见列)
const dynamicColumns = computed(() => {
return columnOptions.value
.filter(col => col.visible)
.sort((a, b) => a.order - b.order)
})
// 处理列更新
const handleColumnsUpdate = (newColumns) => {
columnOptions.value = newColumns
}
</script>
关键技术点解析
1. 动态列渲染原理
动态列的核心是根据配置动态生成 el-table-column
组件:
javascript
const dynamicColumns = computed(() => {
return columnOptions.value
.filter(col => col.visible) // 过滤出可见的列
.sort((a, b) => a.order - b.order) // 按顺序排序
})
2. 列配置的数据结构
每个列配置包含以下属性:
typescript
interface ColumnConfig {
prop: string // 字段名
label: string // 显示名称
width?: number // 列宽
minWidth?: number // 最小宽度
align?: 'left' | 'center' | 'right' // 对齐方式
fixed?: 'left' | 'right' // 固定位置
sortable?: boolean // 是否可排序
visible: boolean // 是否显示
order: number // 排序序号
slot?: boolean // 是否使用插槽
formatter?: boolean // 是否需要格式化
showAdvanced?: boolean // 是否显示高级设置
}
最佳实践建议
-
性能优化:
- 对于大数据量的表格,使用虚拟滚动
- 避免在列配置中使用复杂的计算属性
-
用户体验:
- 提供配置导入/导出功能
- 添加配置保存成功的提示
- 考虑添加撤销/重做功能
-
可访问性:
- 为拖拽手柄添加ARIA标签
- 确保对话框可以通过键盘操作
-
错误处理:
- 验证列配置的合法性
- 提供默认配置回退机制
效果演示


总结
本文介绍了一个基于 Vue 3 和 Element Plus 的动态表格列配置组件的完整实现方案。通过将功能拆分为多个组件,我们实现了可维护的表格列配置的动态表格。关键点包括:
- 使用
vuedraggable
实现列顺序拖拽调整 - 通过计算属性实现动态列过滤和排序
- 利用 Vue 的响应式系统实现配置的双向绑定
- 提供基础和高阶的列配置选项
这种方案可以轻松集成到各种后台管理系统中,大大提升了表格的灵活性和用户体验。开发者可以根据实际需求进一步扩展功能,如添加列分组、条件格式化等高级特性。