Vue3和ElementPlus封装table组件
最近学习vue3.2并自己在写一个项目,然后发现好几个页面都是列表页,重复写table和column也是觉得累,学习的项目列表页不算多,要是公司项目就不一样了,所以就想着自己封装一个table组件,免去大量重复工作和copy改改改。
本文也是仅仅封装了一个相对简单的table组件,主要是table + 分页,要是不想要分页,也是可以通过使用table组件穿参数控制是否展示分页。基于查询表单,后续再安排~
封装一个table组件并不难,主要是搞懂插槽、作用域插槽的写法和用法,下面先复习一下插槽,再进行封装。
一、slot插槽
定义
Vue 实现了一套内容分发的 API,将 元素作为承载分发内容的出口。
简单理解:就是对子组件的扩展,通过 插槽向子组件内部指定位置传递内容。
插槽是组件的一块HTML模板,这块模板显示不显示,怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制。
分类
- 匿名插槽
- 具名插槽
- 作用域插槽
匿名插槽
它不用设置名称属性,可以放置在组件的任意位置;可以理解为父传入样式及内容,子负责展示
<!--index.vue-->
<Child ><ul><li>1</li><li>2</li></ul><ul slot><li v-for="(v,i) in arr" :key="i">{{v}}</li></ul>
</Child><!--child.vue-->
<!--匿名插槽-->
<template><div><slot></slot></div>
</template>
具名插槽
插槽加了名称属性,就变成了具名插槽。 在 v-slot 之后添加冒号 (:) ,然后写出要传递内容的 slot 的名称(v-slot:slotname);简写:#slotname
<!--index.vue-->
<Child><template #default> <!--指定了 default 的名称,表示不需要为默认插槽指定名称;--><p>我是main的内容</p> </template><template #header><h2>艾梯哎教育</h2></template><template #list><h2>列表展示</h2><ul><li v-for="(v,i) in arr" :key="i">{{v}}</li></ul></template>
</Child><!--child.vue-->
<!--具名插槽-->
<slot></slot>
<slot name="header"></slot>
<slot name="list"></slot>
作用域插槽
好理解的叫法:带数据的插槽。
作用域插槽跟单个插槽和具名插槽的区别,因为单个插槽和具名插槽不绑定数据,所以父组件提供的模板一般要既包括样式又包括内容,而作用域插槽,相当于父组件提供一套样式,数据都是子组件的。
<!--index.vue-->
<Child ><template #user="obj"><h2>老师:{{ obj.user.username }}</h2> <h2>所授课程:{{ obj.user.course }}</h2></template><!--解构写法--><template #user="{user}"><h2>老师:{{ user.username }}</h2> <h2>所授课程:{{ user.course }}</h2> </template><!--解构别名--><template #user="{user:person}"><h2>老师:{{ person.username }}</h2> <h2>所授课程:{{ person.course }}</h2> </template></Child><!--child.vue-->
<template><div><slot name="user" :user="user"></slot> </div>
</template><script setup>
import {ref,reactive} from 'vue'
const user = ref({id:1,username:'张老师',course:'vue'});
</script>
二、封装table
理解了具名作用域插槽 之后,相信大家脑海里已经有思路如何封装了。我这里的思路大概如下:
- 接收tableData数据和columns列以及其他杂七杂八的配置项;
- 然后在el-table-column上循环columns列;
- 然后定义以列名为名称的插槽,并将数据row传递出去;
- 并提供默认插槽内容,当没特殊数据展示,可不传父的内容,直接使用 定义的默认内容;
- 如果 columns传入fommater,则会根据传入的function进行转换数据。
具体实现如下:
<!--MyTable-->
<template><div><el-table :style="{ width: '100%' }"ref="elTableRef":data="tableData" :height="height" :max-height="maxHeight":stripe="stripe":row-key="rowKey":highlight-current-row="highlightCurrentRow"@row-click="handleRowClick"@selection-change="handleSelectionChange"><el-table-column v-for="item in columns" :key="item.prop":prop="item.prop" :label="item.label":show-overflow-tooltip="item.showOverflowTooltip":width="item.width":fixed="item.fixed":type="item.type":sortable="item.sortable":selectable="item.selectableFn"><!-- type 对应列的类型。 如果设置了selection则显示多选框; --><!-- 如果设置了 index 则显示该行的索引(从 1 开始计算); --><!-- 如果设置了 expand 则显示为一个可展开的按钮--><!-- selection / index / expand --><template #default="{row, column, $index}" v-if="item.type==='index'">{{getIndex($index)}}</template><template #default="{row, column, $index}" v-if="!item.type"><!-- 具名作用域插槽 --><slot :name="item.prop":slotProps="row":index="$index"><!-- 默认内容,当父组件不传内容时默认显示该内容 --><span v-if="item.formatter">{{ item.formatter(row[item.prop]) }}</span><span v-else>{{ row[item.prop] }}</span></slot></template></el-table-column></el-table><div class="pagination-wrap"><el-paginationv-if="hasPagination"v-model:current-page="currentPage"v-model:page-size="pageSize":page-sizes="pageSizes":small="small":background="true":layout="layout":total="total"@size-change="handleSizeChange"@current-change="handleCurrentChange"/></div></div>
</template><script setup>
import {toRefs} from 'vue'
const props = defineProps({// 表格相关tableData: {type: Array,default: []},columns:{type: Array,default: []},height: {type: String,default: '500px'},maxHeight: {type: String,default: '500px'},stripe: {type: Boolean,default: true},rowKey: {type: String,default: 'id'},highlightCurrentRow: {type: Boolean,default: true},// 分页相关hasPagination: {type:Boolean,default: true},total: {type: Number,default: 0},currentPage: {type: Number,default: 1},pageSize: {type:Number,default: 10},pageSizes: {type: Array,default: [10, 20, 50, 100, 200]},layout: {type: String,default: 'total, sizes, prev, pager, next, jumper'},small: {type: String,default: 'small'}
})let {tableData,columns,height,maxHeight,stripe,rowKey,highlightCurrentRow,hasPagination,total,currentPage,pageSize,pageSizes,layout,small
} = toRefs(props)const emit = defineEmits(['rowClick','selectChange','changeTableData','update:currentPage','update:pageSize'])
// 当某一行被点击时会触发该事件
const handleRowClick = (row, column, event) => {emit('rowClick', { row, column, event })
}
// 当选择项发生变化时会触发该事件
const handleSelectionChange = (selection) => {emit('selectChange', selection)
}// 每页条数变化的事件
const handleSizeChange = (val) => {emit('update:pageSize',val)emit('changeTableData', currentPage.value, val)
}
// 当前页码变化的事件
const handleCurrentChange = (val) => {emit('update:currentPage',val)emit('changeTableData', val, pageSize.value)
}const getIndex = (index)=> {return index + 1 + (currentPage.value - 1) * pageSize.value
}</script><style lang="scss" scoped></style>
三、使用MyTable组件
因为check需要格式化内容并且用el-tag来进行展示内容,所以此处向table组件传入了需要展示的内容,此时,向table的name=check的插槽传入内容,那么table组件的默认展示内容则失效。
同理,由于每个taable组件的操作项也不一样,所以此处向name=operator的slot插入内容。
<MyTable :tableData="tableData":columns="columns":total="total":currentPage="listQuery.pageNo":pageSize="listQuery.pageSize"@changeTableData="changeTableData"><template #check="{ slotProps }"><el-tag class="ml-2" :type="slotProps.check?'success':'danger'">{{ checkFilter(slotProps.check) }}</el-tag></template><template #operator="{slotProps}"><el-button type="primary" @click="setData('edit',slotProps)">编辑</el-button><el-button type="danger" @click="handleDel(slotProps)">删除</el-button></template>
</MyTable><script setup>
import { ref,onMounted } from 'vue'
import MyTable from '@/components/table/index.vue'
import useHooks from '@/hooks'const { checkFilter, dateFormate } = useHooks()let listQuery = ref({pageNo:1,pageSize: 10
})
const tableData = ref([])
let total = ref(0)/*** prop:数据项列名* label:列名展示名* fixed:固定列 true/right/left* width:列宽* show-overflow-tooltip* type:对应列的类型 selection / index / expand* sortable:true/false* selectable:Function* formatter:格式化内容 function(row, column, cellValue, index)
**/
let columns = ref([{prop: 'number',label: '车牌自编号'},{prop: 'numberplate',label: '车牌号'},{prop: 'date',label: '出厂日期',formatter: dateFormate},{prop: 'check',label: '车辆状态'},{prop: 'operator',label: '操作',fixed: "right"},
])onMounted(() => {getCarList()
})const changeTableData = (pageNum,pageSize) => {listQuery.value.pageNo = pageNumlistQuery.value.pageSize = pageSizegetCarList()
}// 列表查询
async function getCarList() {const {data: {data}} = await carList(listQuery.value)tableData.value = data.listtotal.value = data.rows
}</script>
效果如下:
如果需要加上索引或者复选框,需要在columns上添加上
{type: 'selection',label:'',width: '50px'},{type: 'index',label:'序号',width: '60px'},
若是列项超长不需要tooltip,则配置showOverflowTooltip为false(默认是true)
{prop: 'number',label: '车牌自编号',showOverflowTooltip: true, width: '100px'},
到此一个talbe组件就封装完成,如有不当的地方还请大家多多包含和赐教!如大家有不一样的封装思想也多多留言交流,互相学习互相进步。
相关文章:
Vue3和ElementPlus封装table组件
最近学习vue3.2并自己在写一个项目,然后发现好几个页面都是列表页,重复写table和column也是觉得累,学习的项目列表页不算多,要是公司项目就不一样了,所以就想着自己封装一个table组件,免去大量重复工作和co…...
第一篇:参考资料地址
javaGuide JavaGuide(Java学习&面试指南) | JavaGuide 清华学生总结的 小林coding labuladong labuladong 的算法笔记 | labuladong 的算法笔记 【华仔说技术】kafka的系列文章 https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg3MTcxMDgxNA…...
wordpress 开源主题
海外就医wordpress主题 出国看病、海外就医是越来越多中产家庭的选择,此wordpress主题适合做相关业务的公司官网。 https://www.jianzhanpress.com/?p5220 防护wordpress外贸主题 个人防护器具wordpress外贸主题,适合做劳动保护的外贸公司使用。 ht…...
【Linux网络命令系列】ping curl telnet三剑客
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
于月仙主动与赵本山握手表示欢迎,赵:怎么着要跟我第二次牵手啊?
于月仙主动与赵本山握手表示欢迎,赵:怎么着要跟我第二次牵手啊? --小品《乡村爱情》(中1)的台词 表演者:赵本山 于月仙 王小利 唐鉴军等 (接上) 咱们呢就给新人揭盖头 好 好长贵…...
Unity UGUI之Slider基本了解
在Unity中,Slider(滑动条)是一种常用的用户界面控件之一,允许用户通过拖动滑块来选择一个数值。常常应用于调节数值(如调节音量、亮度、游戏难度等)、设置选项等。 以下是Slider的基本信息和用法: 1、创建…...
【Linux】进程间通信之共享内存
文章目录 引入共享内存的原理共享内存的相关接口shmget()shmat()shmdt()shmctl() 共享内存的简单使用共享内存的特点 引入 进程间通信,顾名思义就是一个进程和另一个进程之间进行对话,以此完成数据传输、资源共享、通知事件或进程控制等。 众所周知&am…...
文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于条件风险价值的虚拟电厂参与能量及备用市场的双层随机优化》
本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 这篇文章的标题涉及到以下几个关键点…...
前端架构: 脚手架通用框架封装之CommonJS和ESM混合开发兼容解决(教程五)
CommonJS 和 ESModule 混合开发 接上文,仍旧在 abc-cli 项目中参考:https://blog.csdn.net/Tyro_java/article/details/136433159现在要在脚手架项目中安装 chalk 依赖,因为在 abc-cli 项目几乎都是 CommonJS的实现而 chalk 这个依赖源码是基…...
基于主从模式的Reactor的仿muduo网络库
🌇个人主页:平凡的小苏 📚学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风…...
Linux服务器搭建超简易跳板机连接阿里云服务器
简介 想要规范内部连接阿里云云服务器的方式,但是最近懒病犯了,先搞一个简易式的跳板机过渡一下,顺便在出一个教程,其他以后再说! 配置方法 创建密钥 登录阿里云,找到云服务器ECS控制台,点击…...
Windows Server 各版本搭建文件服务器实现共享文件(03~19)
一、Windows Server 2003 打开服务器,点击左下角开始➡管理工具➡管理您的服务器➡添加或删除角色 点击下一步等待测试 勾选自定义配置,点击下一步 选择文件服务器,点击下一步 勾选设置默认磁盘空间,数据自己更改,最…...
ARM总结and复习
安装交叉编译工具链 a. 为什么安装 因为arm公司的指令集在不断迭代升级,指令集日益增多,而架构是基于指令集研发的,所以架构不一样,指令集也不一样 eg:arm架构使用的是arm指令集 x86架构使用的是x86指令集 而我们日常开发环境中linux的架构…...
非功能测试的定义、类型和示例
软件已从推动者转变为不同行业企业成功的核心支柱。因此,非功能测试活动成为人们关注的焦点。然而,许多技术和质量保证专业人员并没有意识到非功能测试的必要性。 他们必须了解什么是非功能测试以及为什么必须鼓励将其作为企业应用程序开发项目的实践。…...
Angular基础---HelloWorld---Day1
文章目录 1. 创建Angular 项目2.对Angular架构的最基本了解3.创建并引用新的组件(component)4.对Angular架构新的认识(多组件)5.组件中业务逻辑文件的编辑(ts文件)6.标签中属性的绑定(1) ID的绑定(2) class…...
k8s部署项目常见的问题及解决方案
在Kubernetes(k8s)部署项目中,确实存在一些常见问题和挑战。以下是这些问题及其相应的解决方案: 网络插件问题: 问题:网络插件配置不当或版本不兼容可能导致Pod间通信问题。解决方案:重新部署或…...
Redis实现乐观锁+秒杀场景demo
在Redis中,乐观锁通常是通过使用 WATCH、MULTI 、EXEC和DISCARD命令实现的。这种乐观锁机制允许客户端在执行事务期间监视一个或多个键,并且只有在事务执行期间没有其他客户端修改被监视的键时,才会执行事务。 应用场景: 库存控…...
阅读笔记 | Transformers in Time Series: A Survey
阅读论文: Wen, Qingsong, et al. “Transformers in time series: A survey.” arXiv preprint arXiv:2202.07125 (2022). 这篇综述主要对基于Transformer的时序建模方法进行介绍。论文首先简单介绍了Transformer的基本原理,包括位置编码、多头注意力机…...
WPF MVVM中List<>和ObservableCollection<>的区别与对比分析
在WPF MVVM(模型-视图-视图模型)架构中,数据绑定是实现UI与后端逻辑分离的关键特性。为了使UI能够响应后端数据的变化,通常需要用到特定的集合类型。在WPF中,最常见的两种集合类型是List< T>和ObservableCollect…...
python给企微发消息
方法一:webhook方式。使用群机器人给企微群发消息 import requestsdef qwxsendmessage(msg):urlhttps://qyapi.weixin.qq.com/cgi-bin/webhook/send?key6c598840-804a-4eb5-a999-a023313 #url换成自己群机器人的webhookurldata{msgtype:text,text:{content:msg}}…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
