Vue 3 + Element Plus 实现可定制的动态表格列配置组件

引言

在后台管理系统中,表格是最常用的数据展示方式之一。不同的用户或不同的场景下,我们往往需要展示不同的表格列,或者对列的显示方式有不同的需求。本文将介绍如何基于 Vue 3 和 Element Plus 实现一个可定制的动态表格列配置组件,让用户可以自由选择需要显示的列、调整列的顺序、配置列的显示方式等。

组件设计思路

我们的动态表格列配置组件主要由三部分组成:

  1. CustomizeTableColumns - 负责单个表格列的渲染
  2. ColumnConfigDialog - 提供列配置的交互界面
  3. 主页面 - 整合组件并提供数据

这种设计遵循了单一职责原则,每个组件只关注自己的核心功能,使得代码更加清晰、易于维护。

核心组件实现

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>

功能特点

  1. 列可见性控制:可以勾选显示/隐藏列
  2. 拖拽排序 :使用 vuedraggable 实现列顺序调整
  3. 基础配置:可以修改列名、对齐方式、宽度等
  4. 高级配置:支持固定列、最小宽度、排序等高级设置
  5. 全选/重置:一键全选或重置为默认配置

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 // 是否显示高级设置
}

最佳实践建议

  1. 性能优化

    • 对于大数据量的表格,使用虚拟滚动
    • 避免在列配置中使用复杂的计算属性
  2. 用户体验

    • 提供配置导入/导出功能
    • 添加配置保存成功的提示
    • 考虑添加撤销/重做功能
  3. 可访问性

    • 为拖拽手柄添加ARIA标签
    • 确保对话框可以通过键盘操作
  4. 错误处理

    • 验证列配置的合法性
    • 提供默认配置回退机制

效果演示

总结

本文介绍了一个基于 Vue 3 和 Element Plus 的动态表格列配置组件的完整实现方案。通过将功能拆分为多个组件,我们实现了可维护的表格列配置的动态表格。关键点包括:

  1. 使用 vuedraggable 实现列顺序拖拽调整
  2. 通过计算属性实现动态列过滤和排序
  3. 利用 Vue 的响应式系统实现配置的双向绑定
  4. 提供基础和高阶的列配置选项

这种方案可以轻松集成到各种后台管理系统中,大大提升了表格的灵活性和用户体验。开发者可以根据实际需求进一步扩展功能,如添加列分组、条件格式化等高级特性。

相关推荐
烟雨迷4 分钟前
web自动化测试(selenium)
运维·开发语言·前端·python·selenium·测试工具
wow_DG10 分钟前
【Vue2 ✨】Vue2 入门之旅(九):Vue Router 入门
前端·javascript·vue.js
OpenTiny社区1 小时前
“AI 乱炖等于没 AI?”这些AI知识图谱教你秒锁正确场景
前端·开源·agent
zkkkkkkkkkkkkk1 小时前
vue组件中实现鼠标右键弹出自定义菜单栏
javascript·vue.js·vue
维维酱2 小时前
useMemo 实现原理
前端·react.js
夕水2 小时前
原生js实现常规ui组件之checkbox篇
前端·javascript
编程二级爱好者2 小时前
2025年9月计算机二级Web程序设计——选择题打卡Day5
前端·计算机二级
Tanjc5182 小时前
uniapp H5预览图片组件
前端·vue.js·uni-app
ᥬ 小月亮2 小时前
uniapp中输入金额的过滤(只允许输入数字和小数点)
前端·css·uni-app
共享ui设计和前端开发2 小时前
UI前端大数据可视化实战策略:如何设计符合用户认知的数据可视化界面?
前端·ui·信息可视化