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-inputv-model="searchText"placeholder="搜索列"clearablestyle="margin-bottom: 16px"/><draggable v-model="currentColumns" item-key="prop" @end="handleDragEnd"><template #item="{ element: col }"><divv-if="col.label.toLowerCase().includes(searchText.toLowerCase())"class="column-item"><el-checkbox v-model="col.visible">{{ col.label }}</el-checkbox><el-input-numberv-if="col.visible"v-model="col.width":min="50":max="500"style="margin-left: 16px"placeholder="列宽"/><el-checkboxv-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-columnv-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>

效果图展示

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/17106.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于qtcreator的安装过程遇到的问题和处理方法

打算开发个对windows兼容性好的软件&#xff0c;最终决定用c语言&#xff0c;后来选择了qt&#xff0c;发现qt有个不错的东西qt quick&#xff0c;界面图形效果表现的不错&#xff0c;还能做动画&#xff0c;甚至可以做成游戏。 于是打算安装这个软件&#xff0c;软件虽然开源…

一文通俗理解为什么需要泛型以及泛型的使用

为什么需要泛型&#xff1f; public static void main(String[] args) {ArrayList list new ArrayList();// 由于集合没有做任何限定&#xff0c;任何类型都可以给其中存放list.add("abc");list.add("def");list.add(5);Iterator it list.iterator();wh…

HtmlRAG:RAG系统中,HTML比纯文本效果更好

HtmlRAG 方法通过使用 HTML 而不是纯文本来增强 RAG 系统中的知识表示能力。通过 HTML 清洗和两步块树修剪方法&#xff0c;在保持关键信息的同时缩短了 HTML 文档的长度。这种方法优于现有基于纯文本的RAG的性能。 方法 其实主要看下围绕html提纯思路&#xff0c;将提纯后的…

KEPServerEX 中信道深入介绍

以下是 KEPServerEX 中信道&#xff08;Channel&#xff09; 的详细介绍&#xff0c;涵盖其定义、功能、配置步骤及最佳实践&#xff0c;帮助您快速掌握信道在数据采集中的核心作用&#xff1a; 一、信道&#xff08;Channel&#xff09;的定义 信道 是 KEPServerEX 中 连接物…

C#(Winform)通过添加AForge添加并使用系统摄像机

先展示效果 AForge介绍 AForge是一个专门为开发者和研究者基于C#框架设计的, 也是NET平台下的开源计算机视觉和人工智能库 它提供了许多常用的图像处理和视频处理算法、机器学习和神经网络模型&#xff0c;并且具有高效、易用、稳定等特点。 AForge主要包括: 计算机视觉与人…

迅为RK3568开发板篇OpenHarmony实操HDF驱动配置LED-LED测试

将编译好的镜像全部进行烧写&#xff0c;镜像在源码根目录 out/rk3568/packages/phone/images/目录下。 烧写完成之后&#xff0c;在调试串口查看打印日志&#xff0c;如下图所示&#xff1a; 然后打开 hdc 工具&#xff0c;运行测试程序&#xff0c;输入“led_test 1”&…

在VS2022中配置DirectX12环境,并显示显示一个窗口

1.创建空项目并配置项目&#xff1a; 1.打开VS2022,创建C项目中的空项目 2.新建一个Main.cpp文件 3.配置项目 将属性页的C/C项中的语言栏的符合模式设置为否 再将链接器中的系统栏的子系统设置为窗口 设置完成&#xff01; 2.创建一个Windows窗口&#xff1a; 代码&#…

AI前端开发:蓬勃发展的机遇与挑战

人工智能&#xff08;AI&#xff09;领域的飞速发展&#xff0c;正深刻地改变着我们的生活方式&#xff0c;也为技术人才&#xff0c;特别是AI代码生成领域的专业人士&#xff0c;带来了前所未有的机遇。而作为AI应用与用户之间桥梁的前端开发&#xff0c;其重要性更是日益凸显…

DeepSeek+即梦 做AI视频

DeepSeek做AI视频 制作流程第一步&#xff1a;DeepSeek 生成视频脚本和分镜 第二步&#xff1a;生成分镜图片绘画提示词第三步&#xff1a;生成分镜图片第四步&#xff1a;使用可灵 AI 工具&#xff0c;将生成的图片转成视频。第五步&#xff1a;剪映成短视频 DeepSeek 真的强&…

数组练习(深入理解、实践数组)

1.练习1&#xff1a;多个字符从两端移动&#xff0c;向中间汇聚 编写代码&#xff0c;演示多个字符从两端移动&#xff0c;向中间汇聚 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<string.h> int main() {//解题思路&#xff1a;//根据题意再…

学习threejs,使用HemisphereLight半球光

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.HemisphereLight 二、…

vue项目使用vite和vue-router实现history路由模式空白页以及404问题

开发项目的时候&#xff0c;我们一般都会使用路由&#xff0c;但是使用hash路由还是history路由成为了两种选择&#xff0c;因为hash路由在url中带有#号&#xff0c;history没有带#号&#xff0c;看起来更加自然美观。但是hash速度更快而且更通用&#xff0c;history需要配置很…

Fiori APP配置中的Semantic object 小bug

在配置自开发程序的Fiori Tile时&#xff0c;需要填入Semantic Object。正常来说&#xff0c;是需要通过事务代码/N/UI2/SEMOBJ来提前新建的。 但是在S4 2022中&#xff0c;似乎存在一个bug&#xff0c;即无需新建也能输入自定义的Semantic Object。 如下&#xff0c;当我们任…

芯片设计企业的IT支撑点

对于一个芯片设计企业&#xff0c;需要怎么样的IT支撑&#xff0c;这看起来并不是那么重要&#xff0c;并不影响芯片企业是否取得成功&#xff0c;但真正进入这个行业&#xff0c;你会发现&#xff0c;这里还是有一些门道的。 实际上&#xff0c;芯片设计企业对于IT的依赖很重&…

生成对抗网络入门:Mnist手写数字生成

本文为为&#x1f517;365天深度学习训练营内部文章 原作者&#xff1a;K同学啊 一 理论基础 生成对抗网络(Generative Adversarial Networks,GAN)是近年来深度学习领域的一个热点方向。 GAN并不指代某一个具体的神经网络&#xff0c;而是指一类基于博弈思想而设计的神经网络。…

22.4、Web应用漏洞分析与防护

目录 Web应用安全概述DWASP Top 10Web应用漏洞防护 - 跨站脚本攻击XSSWeb应用漏洞防护 - SQL注入Web应用漏洞防护 - 文件上传漏洞Web应用漏洞防护 - 跨站脚本攻击XSS Web应用安全概述 技术安全漏洞&#xff0c;主要是因为技术处理不当而产生的安全隐患&#xff0c;比如SQL注入…

软件的生命周期和需求

什么是软件的生命周期? 定义(描述) --> 创建 --> 使用 --> 销毁 (这一整个过程就是事物的生命周期) 生命周期 那么软件的生命周期又分为哪些呢? 一共分为十步: 可行性研究: 通过分析软件开发要求,确定软件项目的性质、目标和规模,得出可行性研究报告,如果可行性研…

深入理解DeepSeek与企业实践(二):32B多卡推理的原理、硬件散热与性能实测

前言 在《深入理解 DeepSeek 与企业实践&#xff08;一&#xff09;&#xff1a;蒸馏、部署与评测》文章中&#xff0c;我们详细介绍了深度模型的蒸馏、量化技术&#xff0c;以及 7B 模型的部署基础&#xff0c;通常单张 GPU 显存即可满足7B模型完整参数的运行需求。然而&…

Java 字符编码与解码:深入理解 Charset 类

目录 引言 一、什么是字符集&#xff08;Charset&#xff09;&#xff1f; 二、Charset 类的核心功能 1. 获取字符集实例 2. 编码与解码 示例1&#xff1a;字符串转字节数组 示例2&#xff1a;处理不同字符集的乱码问题 3. 字符集检测与支持 三、Charset 类的常用方法…

Redis7.0八种数据结构底层原理

导读 本文介绍redis应用数据结构与物理存储结构,共八种应用数据结构和 一. 内部数据结构 1. sds sds是redis自己设计的字符串结构有以下特点: jemalloc内存管理预分配冗余空间二进制安全(c原生使用\0作为结尾标识,所以无法直接存储\0)动态计数类型(根据字符串长度动态选择…