vue3封装el-table及实现表头自定义筛选

带完善内容


提示:二合一,封装el-table以及给表头配置类自定义筛选和排序

文章目录

  • 一、pandas是什么?


一、pandas是什么?

el-table.vue

<template><div class="page-view"><el-table v-loading="tableData.tableLoading" ref="multipleTableRef" class="jg-table" :data="tableData.data"style="width: 100%;" @selection-change="handleSelectionChange" @row-click="rowClick" @sort-change="sortChange"><template v-for="(item, index) in  tableData.columnsData " :key="index"><!-- 多选 --><el-table-column v-if="item.type === 'selection'" :type="item.type" :width="item.width" /><!-- 单选 --><el-table-column v-else-if="item.type === 'radio'" :width="item.width" class-name="no-radio-label"><template #default="{ row, $index }"><el-radio @change="changeRadio" v-model="radioIndex" :label="$index"></el-radio></template></el-table-column><!-- 渲染formatter --><!-- <el-table-column v-else :property="item.field" :label="item.title" :width="item.width":min-width="item.minWidth" :max-idth="item.maxWidth" :showOverflowTooltip="item.showOverflowTooltip":sortable="item.sortable" :formatter="item.formatter" /> --><el-table-column v-else :property="item.field" :label="item.title" :width="item.width":min-width="item.minWidth" :max-idth="item.maxWidth" :showOverflowTooltip="item.showOverflowTooltip":sortable="item.sortable" :formatter="item.formatter"><template #header><div class="table-header-div"><span class="title-span">{{ item.title }}</span><!-- 控制筛选按钮显隐 --><template v-if="item.field !== 'actionBtn'"><el-popover :visible="visible && item.field === showKey" :virtual-ref="refName" placement="bottom":width="'fit-content'"><template #reference><el-icon class="icon-span" :id="item.field" @click.stop="toggleNameFilter(item.field)"style="cursor: pointer; margin-left: 10px;":style="{ color: searchData[item.field] ? '#007d7b' : '#85888e' }"><Filter /></el-icon></template><div><!-- 输入 --><el-input v-if="item.formType === 'input'" v-model="searchData[item.field]" placeholder="输入框"@input="applyNameFilter" clearable style="margin-top: 10px; width: 150px;" /><!-- 下拉 --><el-select v-if="item.formType === 'select' || item.formType === 'radio'" filterablev-model="searchData[item.field]" placeholder="Select Tag" @change="applyTagFilter" clearablestyle="margin-top: 10px; width: 150px;"><el-option v-for="item in item.selectList" :key="item" :value="item.value" :label="item.name" /></el-select><!-- 多选下拉 --><el-select v-if="item.formType === 'selectMultiple'" multiple filterable collapse-tagsv-model="searchData[item.field]" placeholder="Select Tag" clearablestyle="margin-top: 10px; width: 150px;"><el-option v-for="item in item.selectList" :key="item" :value="item.value" :label="item.name" /></el-select><!-- 日期 && 日期时间 --><el-date-picker v-if="item.formType === 'daterange' || item.formType === 'datetimerange'"style="width: 240px;" v-model="searchData[item.field]" :type="item.formType" range-separator="~"start-placeholder="开始时间" end-placeholder="结束时间" :format="item.dateType"@change="changeData($event, item.field, item.dateType)" /><div class="mt" style="text-align: right;"><el-button type="info" link @click="cancelFilter">重置</el-button><el-button type="primary" link @click="searchFilter">筛选</el-button></div></div></el-popover></template></div></template></el-table-column></template></el-table><pre>{{ {...searchData,...sortObj} }}</pre><pre>{{ tableData }}</pre></div>
</template><script setup lang="jsx">
import { ref, defineOptions, defineEmits, defineProps, watch, } from 'vue' // 按需引入ref函数
import { Filter } from '@element-plus/icons-vue'
import _ from 'lodash'
import moment from 'moment'defineOptions({name: "JgTable"
})const emit = defineEmits(['setSearchData', 'update:editItem', 'update:handleSelectionChange', 'update:changeRadio', 'update:sortChange'])const props = defineProps({description: {type: String,default: () => {return ' '}},tableDataObj: {type: Object,default: () => {return {}}},
})let tableFlag = ref(false)//确保拿到父传子的表格数据再渲染
let tableData = ref({})
let radioIndex = ref(null)let searchData = ref({}) // 搜索参数 每个表头字段
let sortObj = ref({}) // 排序// 时间格式化
const changeData = (value, key, dateType) => {// console.log(value, key, dateType);if (!_.isEmpty(value)) {searchData.value[key][0] = value[0] ? moment(value[0]).format(dateType) : ''searchData.value[key][1] = value[1] ? moment(value[1]).format(dateType) : ''} else {searchData.value[key] = []}
}const showKey = ref(undefined) // 当前展示哪个筛选窗
const visible = ref(false) // 手动控制筛选窗显隐
const refName = ref(null) // 动态绑定在哪个表头图标下// 全局重置
const resetFilters = () => {// searchData.value.nameFilter = {}for (const key in searchData.value) {if (Object.hasOwnProperty.call(searchData.value, key)) {searchData.value[key] = undefined}}applyNameFilter()applyTagFilter()getData()
}// 触发筛选
const toggleNameFilter = (key) => {if (showKey.value !== key) {visible.value = falsegetData()}// console.log(11, document.querySelector(`[ref="${key}"]`));// showKey.value = document.querySelector(`[ref="${key}"]`)// console.log(document.getElementById(key));refName.value = document.getElementById(key)// refName.value = document.querySelector(`[ref="${key}"]`)// refName.value = keyshowKey.value = keyvisible.value = !visible.value}// 点击其他元素
const handleClickOutside = () => {// visible.value = false;
};// 重置
const cancelFilter = () => {searchData.value[showKey.value] = undefinedvisible.value = false;getData()
}
// 筛选
const searchFilter = () => {visible.value = false;getData()
}// 单独过滤
const applyNameFilter = () => {// Filtering logic can be customized if needed
}
const applyTagFilter = () => {// Filtering logic can be customized if needed
}const getData = () => {console.log('筛选参数', { ...searchData.value, ...sortObj.value });emit('setSearchData', { ...searchData.value, ...sortObj.value })
}watch([() => props.tableDataObj, () => props.rulesData], ([tableDataObj, rulesData]) => {// console.log('监听');tableFlag.value = falsetableData.value = _.cloneDeep(tableDataObj) // 使用lodash的深拷贝方法tableFlag.value = truetableDataObj?.columnsData.forEach(ele => {if (ele.field) {searchData.value[ele.field] = undefined}})
}, { deep: true, immediate: true })// 多选
const handleSelectionChange = (val) => {// console.log(val);// 子传父emit('update:handleSelectionChange', val);
}
// 单选
const changeRadio = (val) => {// console.log('单选', val, radioIndex.value.aa);let item = tableData.value.data?.[val] || {}emit('update:changeRadio', item);
}// 表格点击事件
const rowClick = (val) => {// console.log(val);
}// 排序
const sortChange = (val) => {// console.log(val, val.prop, val.order);sortObj.value = {}if (!_.isEmpty(val)) {sortObj.value[val.prop + 'Sort'] = val.order}getData() // 直接统一在筛选里加入排序字段// emit('update:sortChange', sortObj.value) // 不再单独传递排序字段
}</script>
<style lang="scss" scoped>
:deep(.el-table) {thead {.cell {// background-color: #1fff;display: flex;min-width: 100px;position: relative;.table-header-div {// display: inline-block;// align-items: center;flex: 1;display: flex;// white-space: nowrap;.title-span {flex-grow: 1;word-break: break-word;/* 允许单词在任何地方断行 */}.icon-span {flex-shrink: 0;margin-top: 4px;/* 防止缩小 *//* 给图标和标题之间添加一些间距 */}}.caret-wrapper {margin-top: 5px;}}}
}// :deep(.el-table) {
//   thead {
//     .cell {//       .table-header-div {
//         display: inline-block;//         .title-span {
//         }
//       }//       .caret-wrapper {
//         margin-top: -2px;
//       }
//     }
//   }
// }// :deep(.el-table) {
//   thead {
//     .cell {
//       // display: flex;//       .table-header-div {
//         // flex: 1;
//         display: flex;//         .title-span {
//           // flex: 1;
//           white-space: nowrap!important;
//           text-overflow: ellipsis!important;
//           overflow: hidden!important;
//           word-break: break-all!important;
//         }//         .icon-span {}
//       }//       .caret-wrapper {
//         margin-top: 5px;//       }
//     }
//   }
// }// 去除单选框的内容
:deep(.no-radio-label) {.el-radio__label {display: none;}
}
</style>

index.vue

<template><JgTable :tableDataObj="tableData" @setSearchData="setSearchData" @update:editItem="updateEditItem"@update:handleSelectionChange="updateHandleSelectionChange" @update:changeRadio="updateChangeRadio"@update:sortChange="updateSortChange"></JgTable>
</template>
<script setup lang="jsx">
import { ref, defineComponent, toRefs, reactive, onMounted, getCurrentInstance } from 'vue'
import { Delete, Edit, Download, QuestionFilled, EditPen, Tickets } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'defineOptions({name: 'EquipmentDefect'
})
const nameList = ref([])let tableData = ref({tableLoading: false,// title:名称 field:key type:单选复选框 width minWidth maxWidth showOverflowTooltip formatter:格式化内容columnsData: [{ title: '多选', type: 'selection', width: 55 },{ title: '单选', type: 'radio', width: 55 },{ title: '缺陷名称', field: 'aa', formType: 'input', sortable: 'custom', width: 120 },{ title: '缺陷描述', field: 'bb', formType: 'input', sortable: 'custom', showOverflowTooltip: true },{ title: '缺陷发布时间', field: 'cc1', formType: 'daterange', sortable: 'custom', dateType: 'YYYY-MM-DD', width: 140 },{ title: '缺陷发布时间2', field: 'cc2', formType: 'datetimerange', sortable: 'custom', dateType: 'YYYY-MM-DD HH:mm:ss', width: 150 },// { title: '缺陷发布时间',  field: 'cc1', formType: 'datetime',sortable: 'custom',  dateType: 'YYYY-MM-DD HH:mm:ss' },{title: '设备类型', field: 'dd1', formType: 'select', sortable: 'custom', selectList: nameList,formatter: (row) => {const val = nameList.value.find(item => item.value === row.dd1)?.name || ''return [<span>{val}</span>]}},{title: '设备类型多选', field: 'dd2', formType: 'selectMultiple', sortable: 'custom', width: 120, selectList: nameList,formatter: (row) => {const val = filters(row.dd2, nameList.value)return [<span>{val}</span>]}},{ title: '设备厂家', field: 'ee', formType: 'input', sortable: 'custom', },{ title: '设备版本', field: 'ff', formType: 'input', sortable: 'custom', width: 160, showOverflowTooltip: true },{title: '缺陷设备数量缺陷设备数量', field: 'gg', formType: 'input', sortable: 'custom', width: 160,formatter: (row, column) => {// console.log(112,row, column); // 直接{row}或{column} 不会显示内容return [<span onClick={() => clickItem(row, 'view')}> {row.gg} </span>]}},{title: '缺陷反馈状态', field: 'hh', formType: 'radio', sortable: 'custom', minWidth: 200, selectList: [{ name: '已反馈', value: 1 },{ name: '未反馈', value: 0 },],formatter: (row) => (row ? <el-tag style="border: none;" class="cursor" type={row.hh === 1 ? 'primary' : 'warning'}>{row.hh === 1 ? '已反馈' : row.hh === 0 ? '未反馈' : ''}</el-tag> : '')},{title: '缺陷处置进度', field: 'ii', formType: 'progress', sortable: 'custom',formatter: (row) => (<el-progress class="table_progress" width={13} stroke-width={2} type="circle" percentage={row.ii} />)},// {//   title: '测试', field: 'ceshi',width: 200,//   formatter: (row, column) => {//     // console.log(112,row, column); // 直接{row}或{column} 不会显示内容//     return  [<el-tag type={row.ceshi == "可发放" ? "success" : "danger"} onClick={() => editItem(row, 'view')}> {row.ceshi} </el-tag>, <span>{column.label}</span>]//   }// },{title: '操作', field: 'actionBtn', width: 220,formatter: (row) => ([<el-button link type="primary" size="small" icon={Tickets} onClick={() => editItem(row, 'view')} >查看</el-button >,<el-button link type="primary" size="small" icon={EditPen} onClick={() => editItem(row, 'edit')} >编辑</el-button >,<el-button link type="primary" size="small" icon={Delete} onClick={() => editItem(row, 'delete')} >删除</el-button >,])},],data: Array.from({ length: 7 }).map((ele, index) => {return {aa: '客户端不适配',bb: '客户端无法适配凝思 4.2.40',cc1: '2023-7-20',cc2: '2023-7-20 10:10:10',dd1: Math.floor(Math.random() * 5),dd2: [1, 2],ee: '帕拉迪',ff: 'PLD Sys 61012100',gg: Math.floor(Math.random() * 20),hh: Math.floor(Math.random() * 2),ii: Math.floor(Math.random() * 101),ceshi: 123,}})
})const clickItem = (row, type) => {// console.log(row, type);ElMessage({type: 'success',message: '点击',})
}
// 编辑或查看
const editItem = (row, type) => {switch (type) {case 'view':case 'edit':console.log(row, type);break;case 'delete':deleteItem(row, type)break;default:break;}
}// 删除
const deleteItem = (row, type) => {ElMessageBox.confirm('确定删除该列?',{confirmButtonText: '确认',cancelButtonText: '取消',type: 'warning',}).then(() => {ElMessage({type: 'success',message: 'Delete completed',})}).catch(() => {})
}// 拿到搜索条件
const setSearchData = (data) => {console.log(data);
}// 子组件调用父组件的测试事件
const updateEditItem = (data) => {console.log('子组件调用父组件的测试事件', data);editItem(data.row, data.type)
}
const updateHandleSelectionChange = (data) => {console.log('updateHandleSelectionChange', data);
}
const updateChangeRadio = (data) => {console.log('updateChangeRadio', data);
}
const updateSortChange = (data) => {// console.log(data);
}// 下拉过滤回显
const filters = (key, arr = []) => {const names = []const value = Array.isArray(key) ? key : [key]for (let i = 0; i < arr.length; i++) {if (value.includes(arr[i].value)) {names.push(arr[i].name)}}return names.join(';')
}onMounted(() => {setTimeout(() => {nameList.value = [{ name: '横向隔离', value: 0 },{ name: '纵向加密', value: 1 },{ name: '防火墙', value: 2 },{ name: '监测装置', value: 3 },{ name: '运维网关', value: 4 },{ name: '其他', value: 5 },]}, 1000);
})
// 将变量和函数返回,以便在模版中使用</script>
<style lang="scss" scoped></style>

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

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

相关文章

液氮罐搬运过程中的安全注意事项有哪些

在液氮罐搬运过程中&#xff0c;安全性是至关重要的考虑因素。液氮是一种极低温的液体&#xff0c;其温度可达零下196摄氏度&#xff0c;在接触到人体或物体时会迅速引发严重的冷冻伤害。因此&#xff0c;正确的搬运和使用液氮罐是保障操作安全的关键。 液氮是一种无色、无味的…

RK3568笔记四十:设备树

若该文为原创文章&#xff0c;转载请注明原文出处。 一、介绍 设备树 (Device Tree) 的作用就是描述一个硬件平台的硬件资源&#xff0c;一般描述那些不能动态探测到的设备&#xff0c;可以被动态探测到的设备是不需要描述。 设备树可以被 bootloader(uboot) 传递到内核&#x…

分布式服务框架zookeeper+消息队列kafaka

一、zookeeper概述 zookeeper是一个分布式服务框架&#xff0c;它主要是用来解决分布式应用中经常遇到的一些数据管理问题&#xff0c;如&#xff1a;命名服务&#xff0c;状态同步&#xff0c;配置中心&#xff0c;集群管理等。 在分布式环境下&#xff0c;经常需要对应用/服…

项目的一些操作

一、发送qq邮箱验证码以及倒计时 要发送验证码需要用到邮箱的授权码&#xff1a; qq邮箱获取方式&#xff0c;打开qq邮箱点设置找到如下界面&#xff1a; 然后获取授权码&#xff1b; 导入依赖 <dependency><groupId>com.sun.mail</groupId><artifactId&…

cmake configure_package_config_file指令详解

在 CMake 中&#xff0c;configure_package_config_file 命令用于生成包配置文件&#xff08;Package Configuration File&#xff09;&#xff0c;这些文件用于指定如何使用和链接某个库或工具。通常情况下&#xff0c;这些文件用于支持 CMake 的 find_package 命令来查找和加…

LeetCode 算法:单词搜索 c++

原题链接&#x1f517;&#xff1a;单词搜索 难度&#xff1a;中等⭐️⭐️ 题目 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通…

Perl 语言的特点

Perl 语言入门学习可以涵盖多个方面&#xff0c;包括其特点、基本语法、高级特性以及学习资源和社区支持等。以下是一个详细的入门学习指南&#xff1a; 一、Perl 语言的特点 文本处理能力强&#xff1a;Perl 提供了丰富的字符串处理函数和正则表达式的支持&#xff0c;非常适…

[C++]运算符重载

一、运算符重载 在C中&#xff0c;运算符重载&#xff08;Operator Overloading&#xff09;是一种允许程序员为已有的运算符&#xff08;如、-、*、/等&#xff09;赋予特定于类的含义的技术。通过运算符重载&#xff0c;可以使类的使用更加直观和自然&#xff0c;提高代码的…

详解MLOps,从Jupyter开发到生产部署

大家好&#xff0c;Jupyter notebook 是机器学习的便捷工具&#xff0c;但在应用部署方面存在局限。为了提升其可扩展性和稳定性&#xff0c;需结合DevOps和MLOps技术。通过自动化的持续集成和持续交付流程&#xff0c;可将AI应用高效部署至HuggingFace平台。 本文将介绍MLOps…

kotlin compose 实现应用内多语言切换(不重新打开App)

1. 示例图 2.具体实现 如何实现上述示例,且不需要重新打开App ①自定义 MainApplication 实现 Application ,定义两个变量: class MainApplication : Application() { object GlobalDpData { var language: String = "" var defaultLanguage: Strin…

Linux TFTP服务搭建及使用

1、TFTP 服务器介绍 TFTP &#xff08; Trivial File Transfer Protocol &#xff09;即简单文件传输协议是 TCP/IP 协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议&#xff0c;提供不复杂、开销不大的文件传输服务。端口号为 69 2、TFTP 文件传输的特点 tftp…

【无标题】Elasticsearch for windows

一、windows安装Elasticsearch 1、Elasticsearch&#xff1a;用于存储数据、计算和搜索&#xff1b; 2、Logstash/Beats&#xff1a;用于数据搜集 3、Kibana&#xff1a;用于数据可视化 以上三个被称为ELK&#xff0c;常用语日志搜集、系统监控和状态分析 Elasticsearch安…

中英双语介绍“破发”(Breaking below issue price)

中文版 破发是指新发行的股票在上市后&#xff0c;市场交易价格跌破其发行价的现象。具体来说&#xff0c;如果一家公司通过首次公开募股&#xff08;IPO&#xff09;或增发股票等方式在证券市场上发行新股&#xff0c;而新股在二级市场上的交易价格低于其发行时确定的价格&am…

3、宠物商店智能合约实战(truffle智能合约项目实战)

3、宠物商店智能合约实战&#xff08;truffle智能合约项目实战&#xff09; 1-宠物商店环境搭建、运行2-webjs与宠物逻辑实现3-领养智能合约初始化4-宠物领养实现5-更新宠物领养状态 1-宠物商店环境搭建、运行 https://www.trufflesuite.com/boxes/pet-shop 这个还是不行 或者…

ArkUI状态管理

State装饰器 在声明式UI中&#xff0c;是以状态驱动试图更新 状态 (State) 指驱动视图更新的数据(被装饰器标记的变量) 试图(View) 基于UI描述渲染得到用户界面 说明 1.State装饰器标记的变量必须初始化&#xff0c;不能为空 2.State支持Object、classstring、number、b…

[Vulnhub] devt-improved slog_users+vim权限提升+nano权限提升+passwd权限提升+Lxc逃逸权限提升

信息收集 IP AddressOpening Ports192.168.101.149TCP:22,113,139,445,8080 $ nmap -p- 192.168.101.149 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | …

9.11和9.9哪个大?GPT-4o也翻车了

今天刷到了这个问题&#xff0c;心血来潮去问下chatgpt-4o&#xff0c;没想到疯狂翻车... 第一次问&#xff1a; GPT一开始给出了难绷的解答&#xff0c;让我想起了某短视频软件评论区里对某歌手节目排名的质疑哈哈哈哈哈 但是在接下来的进一步询问和回答中它反应过来了。 第…

JavaWeb笔记_Response对象

一.Response对象 1.1 Response对象概述 a.专门负责给浏览器响应信息&#xff08;响应行&#xff0c;响应头&#xff0c;响应体&#xff09;的对象 b.我们主要使用的是跟HTTP协议相关的Response对象&#xff1a;HTTPServletResponse&#xff0c;继承了ServletResponse&#x…

MAVSDK-Java开源库的SDK库macOS平台编译

1.先安装好JDK17 2.克隆MAVSDK-Java源码 3.检测工程./gradlew check 发现未安装protoc-gen-mavsdk 安装后要添加到环境变量 4.安装protoc-gen-mavsdk pip3 install protoc-gen-mavsdk安装路径为: /opt/anaconda3/lib/python3.11/site-packages/protoc_gen_mavsdk

“社群+”生态下的开源AI智能名片源码:驱动商业与社会连接的新引擎

摘要&#xff1a;在“社群”生态日益成为主流趋势的今天&#xff0c;开源AI智能名片源码作为技术创新与社群运营的深度融合体&#xff0c;正逐步展现出其重塑商业格局、深化社会连接的巨大潜力。本文旨在深入探讨开源AI智能名片源码的技术特性、在“社群”生态中的具体应用、对…