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. 提供基础和高阶的列配置选项

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

相关推荐
yangzhi_emo4 分钟前
ES6笔记2
开发语言·前端·javascript
yanlele20 分钟前
我用爬虫抓取了 25 年 5 月掘金热门面试文章
前端·javascript·面试
中微子2 小时前
React状态管理最佳实践
前端
烛阴2 小时前
void 0 的奥秘:解锁 JavaScript 中 undefined 的正确打开方式
前端·javascript
中微子2 小时前
JavaScript 事件与 React 合成事件完全指南:从入门到精通
前端
Hexene...2 小时前
【前端Vue】如何实现echarts图表根据父元素宽度自适应大小
前端·vue.js·echarts
初遇你时动了情2 小时前
腾讯地图 vue3 使用 封装 地图组件
javascript·vue.js·腾讯地图
华子w9089258592 小时前
基于 SpringBoot+VueJS 的农产品研究报告管理系统设计与实现
vue.js·spring boot·后端
天天扭码3 小时前
《很全面的前端面试题》——HTML篇
前端·面试·html
xw53 小时前
我犯了错,我于是为我的uni-app项目引入环境标志
前端·uni-app