当前位置: 首页 > news >正文

el-table封装一个自定义列配置表格组件(vue3开箱即用)

组件核心功能

  • 拖拽排序(使用 vuedraggable

  • 显示/隐藏控制

  • 列宽调整

  • 列固定状态记忆

  • 搜索过滤列

  • 本地存储(localStorage)可改成接口保存

  • 默认配置恢复

  • 通过 searchText 动态过滤列。

安装拖拽依赖

npm install vuedraggable
  • 如果需要支持后端存储,可以在 savePreferences 方法中添加 API 调用。

  • 确保 columns 配置中包含 prop 和 label 字段。

创建组件ColumnVisibilityControl.vue

<template>
  <div class="column-control">
    <el-button @click="showControl = true"
      ><el-icon><Grid /></el-icon
    ></el-button>

    <el-dialog v-model="showControl" title="列配置" width="600px">
      <el-input
        v-model="searchText"
        placeholder="搜索列"
        clearable
        style="margin-bottom: 16px"
      />

      <draggable v-model="currentColumns" item-key="prop" @end="handleDragEnd">
        <template #item="{ element: col }">
          <div
            v-if="col.label.toLowerCase().includes(searchText.toLowerCase())"
            class="column-item"
          >
            <el-checkbox v-model="col.visible">{{ col.label }}</el-checkbox>
            <el-input-number
              v-if="col.visible"
              v-model="col.width"
              :min="50"
              :max="500"
              style="margin-left: 16px"
              placeholder="列宽"
            />
            <el-checkbox
              v-if="col.visible"
              v-model="col.fixed"
              style="margin-left: 16px"
            >
              固定
            </el-checkbox>
          </div>
        </template>
      </draggable>

      <template #footer>
        <el-button @click="resetToDefault">恢复默认</el-button>
        <el-button type="primary" @click="savePreferences">保存</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, watch, onMounted } from "vue";
import { ElMessage } from "element-plus";
import draggable from "vuedraggable";
import {
  Check,
  Delete,
  Edit,
  Message,
  Search,
  Grid,
} from "@element-plus/icons-vue";

const props = defineProps({
  columns: {
    type: Array,
    default: () => [],
    validator: (value) => value.every((col) => "prop" in col && "label" in col),
  },
  storageKey: {
    type: String,
    default: "table-columns-preference",
  },
});

const emit = defineEmits(["columns-change"]);

const showControl = ref(false);
const searchText = ref("");
const currentColumns = ref([]);
const defaultColumns = ref([]);

const initializeColumns = () => {
  defaultColumns.value = JSON.parse(JSON.stringify(props.columns));
  currentColumns.value = JSON.parse(JSON.stringify(props.columns));

  const savedData = localStorage.getItem(props.storageKey);
  if (savedData) {
    try {
      const parsed = JSON.parse(savedData);
      applySavedPreferences(parsed);
    } catch {
      localStorage.removeItem(props.storageKey);
    }
  }
};

const applySavedPreferences = (savedData) => {
  currentColumns.value = props.columns
    .map((col) => {
      const savedCol = savedData.find((c) => c.prop === col.prop);
      return savedCol ? { ...col, ...savedCol } : col;
    })
    .sort((a, b) => a.order - b.order);
};

const updateVisibleColumns = () => {
  const visibleColumns = currentColumns.value
    .filter((col) => col.visible)
    .map((col) => ({
      prop: col.prop,
      label: col.label,
      width: col.width,
      fixed: col.fixed,
    }));
  emit("columns-change", visibleColumns);
};

const handleDragEnd = () => {
  currentColumns.value = currentColumns.value.map((col, index) => ({
    ...col,
    order: index,
  }));
};

const savePreferences = () => {
  const dataToSave = currentColumns.value.map((col) => ({
    prop: col.prop,
    visible: col.visible,
    order: col.order,
    width: col.width,
    fixed: col.fixed,
  }));
  localStorage.setItem(props.storageKey, JSON.stringify(dataToSave));
  showControl.value = false;
  ElMessage.success("配置已保存");
};

const resetToDefault = () => {
  currentColumns.value = JSON.parse(JSON.stringify(defaultColumns.value));
  localStorage.removeItem(props.storageKey);
  ElMessage.success("已恢复默认配置");
};

watch(
  currentColumns,
  () => {
    updateVisibleColumns();
  },
  { deep: true }
);

onMounted(() => {
  initializeColumns();
});
</script>

<style scoped>
.column-item {
  padding: 8px 12px;
  margin: 4px 0;
  background: #f5f7fa;
  border-radius: 4px;
  cursor: move;
  display: flex;
  align-items: center;
}
</style>

组件的使用

<template>
  <div class="about">
    <div>
      <column-control
        :columns="tableColumns"
        storage-key="user-table-preferences"
        @columns-change="handleColumnsChange"
      />

      <el-table :data="tableData" :key="tableKey">
        <el-table-column
          v-for="col in visibleColumns"
          :key="col.prop"
          :prop="col.prop"
          :label="col.label"
          :width="col.width"
          :fixed="col.fixed"
        />
      </el-table>
    </div>
  </div>
</template>
<script setup>
import { ref } from "vue";
import ColumnControl from "./ColumnVisibilityControl.vue";

// 表格数据
const tableData = ref([
  {
    name: "张三",
    age: 25,
    address: "北京",
    sex: "男",
    type: "A",
    phone: "1234567890",
  },
  {
    name: "李四",
    age: 30,
    address: "上海",
    sex: "女",
    type: "B",
    phone: "1234567890",
  },
  {
    name: "王五",
    age: 28,
    address: "重庆",
    sex: "女",
    type: "C",
    phone: "1234567890",
  },
  {
    name: "王刘",
    age: 33,
    address: "广州",
    sex: "女",
    type: "C",
    phone: "1234567890",
  },
  {
    name: "王气",
    age: 88,
    address: "深圳",
    sex: "男",
    type: "D",
    phone: "1234567890",
  },
]);

// 列配置
const tableColumns = [
  { prop: "name", label: "姓名", visible: true, width: 120, fixed: false },
  { prop: "age", label: "年龄", visible: true, width: 100, fixed: false },
  { prop: "address", label: "地址", visible: true, width: 120, fixed: false },
  { prop: "sex", label: "性别", visible: true, width: 120, fixed: false },
  { prop: "type", label: "类别", visible: true, width: 120, fixed: false },
  { prop: "phone", label: "电话", visible: true, width: 120, fixed: false },
];

// 可见列
const visibleColumns = ref([]);
const tableKey = ref(0);

// 列配置变化回调
const handleColumnsChange = (visibleCols) => {
  visibleColumns.value = visibleCols;
  tableKey.value += 1; // 强制刷新表格
};
</script>
<style>
@media (min-width: 1024px) {
  .about {
    min-height: 100vh;
    display: flex;
    align-items: center;
  }
}
</style>

效果图展示

 

 

 

 

 

相关文章:

  • 高速存储文章目录
  • 称呼计算器:智能科技,简化您的计算生活
  • python后端调用Deep Seek API
  • ffmpeg基本用法
  • 图数据库neo4j进阶(一):csv文件导入节点及关系
  • bitcoinjs学习1—P2PKH
  • 【开源免费】基于SpringBoot+Vue.JS工作流程管理系统(JAVA毕业设计)
  • ubuntu20.04+RTX4060Ti大模型环境安装
  • SpringBoot实战:高效获取视频资源
  • chrome://version/
  • c++ 多线程知识汇总
  • 学习笔记-人脸识别相关编程基础
  • Flutter_学习记录_基本组件的使用记录_2
  • JavaScript函数与方法详解
  • 细说STM32F407单片机RTC的备份寄存器原理及使用方法
  • 软件开发 | GitHub企业版常见问题解读
  • Django初始化第二章
  • Unity WebGL包体压缩
  • Win10环境借助DockerDesktop部署最新MySQL9.2
  • 安装 Ollama 需要哪些步骤?(windows+mac+linux+二进制+Docker)
  • 全国重点网络媒体和网络达人走进沧州,探寻“文武双全”的多重魅力
  • 印巴战火LIVE丨“快速接近战争状态”:印度袭击巴军事基地,巴启动反制军事行动
  • 中国象棋协会坚决支持司法机关依法打击涉象棋行业的违法行为
  • 纪念|古文字学泰斗裘锡圭:“还有很多事情要做”
  • 巴基斯坦信德省卡拉奇发生爆炸
  • 全国铁路五一假期累计发送1.51亿人次,多项运输指标创历史新高