Vue3使用JSX封装JSON化ElementUi表格

您所在的位置:网站首页 豪爵150电喷摩托车价格 Vue3使用JSX封装JSON化ElementUi表格

Vue3使用JSX封装JSON化ElementUi表格

2024-07-10 05:05:53| 来源: 网络整理| 查看: 265

最近刚刚好有时间,看见了之间封装的饿了么的表格,感觉之前封装的方法说实在不太理想,于是就有了重构的想法,于是就这样开始了我的重构之旅。

项目环境 "vue": "^3.2.16", "sass":"^1.43.4", "typescript":"^4.4.3" "vite" 复制代码 重构点 JSX + JSON配置生成表格 支持插槽自定义表头,列表项 封装暴露的Api跟官方文档一致 支持分页 初始化

创建一个DynamicTable组件,并且配置好需要由外部传入的配置项

import {defineComponent} from "vue"; import {isEmpty} from "element-plus/es/utils/util"; export default defineComponent({ name: "DynamicTable", props: { // 父组件的实例 parentDom: Object, // 表格项 columns: { type: Array, default: () => ([]) }, // 表格的配置 options: { type: Object, default: () => ([]) }, // 操作按钮组 operations: { type: Object, default: () => ({}) }, // 表格的数据 tableData: { type: Array, default: () => ([]) }, // 分页配置 pagination:{ type:Object, default:()=>({}) } }, 复制代码

可能有人会疑惑,就是parentDom这个父组件实例有什么用?其实,它最主要的作用就是让当前的子组件可以直接调用父组件的方法,避免了使用emit或者是直接将函数体传入配置所会产生的一些问题,而且因为我这里使用的是组合式APi,在setup中是无法获取到当前的this的。 如果你不明白,那么下面会慢慢说明

在开始之前,需要安装一下@vitejs/plugin-vue-jsx这个插件,然后在vite.config.js里面配置一下:

import {defineConfig} from 'vite' import vueJsx from '@vitejs/plugin-vue-jsx' export default defineConfig({ plugins: [ vueJsx({ // options are passed on to @vue/babel-plugin-jsx }), ], ... }) 复制代码 JSX + JSON配置生成表格

首先我们上面定义了很多的prop,我们先来支持根据columns,options来配置和生成表格,并且将tableData传入可以展示数据,上代码:

setup({columns, tableData}, ctx: any) { // 删除掉要自定义的字段 const deleteField = (column: any) => { delete column['align'] return column } return () => ( { columns.map((n: any) => { const {align}: any = n // 可以根据某一列自定义位置 const _align = align || options.align || 'center' // 删除自定义的字段 deleteField(n) return }) } ) } 复制代码

然后测试一下:

const columns:Array = [ {label:'姓名',prop:'name',}, {label:'性别',prop:'sex'}, {label:'年龄', prop:'num',} ] const options = { border:true, } const tableData:Array = [ {name:'1', sex:'男', num:12,}, {name:'2', sex:'男', num:12}, {name:'3', sex:'男', num:12}, ] 复制代码

不出意外,他现在应该长下面这个样子

image.png border是官方的api,主要就是添加线条,那么到这里,我们最基础的功能就完成了,但是在实际的项目开发中,往往有这么几种需求:

需求1:表格的头部要自定义组件 需求2:表格的某一列要自定义组件 需求3:要求操作按钮可以根据当前行进行变化 需求4:表格的操作项需要可以自定义 需求5:表格中的数据需要根据后台返回的状态值得出对应的结果 所以!我们要继续完善我们的组件,来确保在大部分情况下,可以去适应大部分的需求。 添加组件对更多需求的支持

那么就上面的需求而言,个人最大的烦恼点,其实是数据应该如何交互,比如说,我自定义了某个表单项column,假如在其中定义了一个input框,那么我们是不是可以考虑这种可能性,在我修改了input框中的值之后,让表格中的数据同步变动,而不需要我们再去操作一次去修改。 当然上面只是一种可能性,还有比如下拉框,时间选择器等等这些可以随时变动数据的组件,都可以支持同步修改。那这个时候,就需要使用到引用传递这个东西了,关于引用传递大家应该都不陌生了,其实就是引用类型会发生的一个现象,那么我们传入的tableData实际上保存在里面的是对象,就可以使用这个现象来对数据进行操作了。 那么一次性解决上面的需求吧

自定义头部 + 列内容 + 操作项

其实ElementUi官方已经提供了一个render-header的api来支持自定义表头,可是本人呢,就是不喜欢使用JSX或者是h函数来做这些操作,因为在配置项中添加函数,他是没办法获取到当前的实例的,而且对于vue一些api支持也不够优雅,就比如v-model,在h函数中 ,就需要自己自定义一次,关于这部分的内容官网也有说,有兴趣可以自己查找一下。那我们都用vue了,又有插槽这么一个好东西,所以我就干脆将所有的自定义操作都修改成了支持插槽使用。

自定义头部 + 列内容

先来看一下我们希望怎么去使用这个自定义头部,也就是在代码中,如何编写能够节省最多的精力,不需要花费多余的时间去学习新的api,那肯定就是遵循官方文档的写法,而插槽普遍的使用方式如下:

复制代码

所以,我们希望当我们去定义一个头部或者是指定列内容的时候,它能够跟上面一样使用

// 自定义 name 这个column的表格头 我是name的表头 // 自定义 name 这个column的列内容 复制代码

那么为了完成可以支持这样的使用方式,我们可以使用一下slots这个变量,在setup中,它保存在ctx上下文中,然后修改的代码如下:

... export default defineComponent({ name: "DynamicTable", props: { parentDom: Object, // 表格项 columns: { type: Array, default: () => ([]) }, // 表格的配置 options: { type: Object, default: () => ([]) }, // 操作按钮组 operations: { type: Object, default: () => ({}) }, // 表格的数据 tableData: { type: Array, default: () => ([]) }, // 分页配置 pagination:{ type:Object, default:()=>({}) } }, setup({columns, tableData, options, operations, parentDom,pagination}, ctx: any) { // 删除掉要自定义的字段 const deleteField = (column: any) => { delete column['align'] return column } return () => ( { columns.map((n: any) => { const {align}: any = n // 可以根据某一列自定义位置 const _align = align || options.align || 'center' // 删除自定义的字段 deleteField(n) // 定义插槽 const slots = { default: ctx.slots[`${n.prop}_content`] ? ctx.slots[`${n.prop}_content`] : null, header: ctx.slots[`${n.prop}_header`] ? ctx.slots[`${n.prop}_header`] : null } return }) } ) } }) 复制代码

然后测试一下,是否可以自定义表头,列表内容,并且可以自动修改表格项之中的内容,不出意外,现在的界面应该是

image.png 那么从右边可以看见,name这个列的第一项随着我们修改而被修改了,而表格的头部与内容也成功被我们用插槽自定义了。那么到此,我们总算是完成了一个表格最基础功能的百分之60。 从图片可以看见表格左边有多选的功能,那在官方的文档中,当我们多选的时候,可以提供一个函数,来接收当前被选到的行的数据,所以在我们的组件中也必须支持这个功能,那么这个时候,上面所有的parentDom就很有用了,其实子组件触发父组件的函数并且传参的方式也有几种:

使用Emit来触发父组件的函数 在配置项中提供一个函数题以供调用 上面这两种方式算是最常见的使用方式了,可是他们在这种组件中使用,会产生不同的问题。 emit 方式: 使用这个方式,就需要往组件上添加绑定的函数,这就导致写起来不够优化,而且不止需要在组件上绑定函数,还需要在配置项中将需要使用的对应的函数名传入组件中以供调用,那么就多了几步操作,个人不喜欢这样,所以pass掉。 在配置项中提供一个函数体 这个方式如下 ... const options = { name:{ onClick:()=>{ 在这里调用或传入父组件的方法 } } } 复制代码

这个方式的弊端更明显,首先是当前的函数体内的this并不是父组件的实例,所以在onClick中如果想要使用到父组件的数据,那么必须在DynamicTable组件中获取到其$parent,然后回传到onClick函数中,才能调用,多余的传参不说,假如我们在Dialog中使用我们的组件的时候,其$parent获取到的压根不是我们想要的那个实例,所以到这个时候就要使用

const options = { name:{ onClick:(vm)=>{ // 在这里调用或传入父组件的方法 vm.$parent.$parent } } } 复制代码

这样就很蛋疼了,又难看,又违背了简单方便使用的想法,所以最后,我采用了第三种方式,虽然也有一些问题,比如说将大批量的数据传入了另外一个组件,但是对于我们的实际使用上来说,其实不值一提。

直接将父组件的实例传入子组件 最后采用的是这种方案,既可以解决多余的调用的问题,又可以很方便的调用父组件中的方法,还不用担心函数中this的问题。 采用这种方案,需要调用函数的时候,只要在配置项中传入对应触发事件的函数名,那么我们这里还是遵循尽量跟官方文档一致的api这个想法来做,以完成多选功能来完善我们的代码 ... setup({columns, tableData, options, operations, parentDom,pagination}, ctx: any) { // 删除掉要自定义的字段 const deleteField = (column: any) => { delete column['align'] return column } // 专门拿来触发父组件的函数 // handleName:函数名 // params:传入的参数 const handleFn = (handleName:string,params:any = null) => { return parentDom && parentDom[handleName] && parentDom[handleName](params) } return () => ( handleFn(options['selection-change'],selection)} > { columns.map((n: any) => { const {align}: any = n // 可以根据某一列自定义位置 const _align = align || options.align || 'center' // 删除自定义的字段 deleteField(n) // 定义插槽 const slots = { default: ctx.slots[`${n.prop}_content`] ? ctx.slots[`${n.prop}_content`] : null, header: ctx.slots[`${n.prop}_header`] ? ctx.slots[`${n.prop}_header`] : null } return }) } {renderOperations()} { !isEmpty(pagination) && renderPagination()} ) } 复制代码

其实就是当发现选项是selection的时候,就不需要el-table-column最任何操作,但是也要支持原来el-table-column的api,所以在渲染插槽的时候添加一下判断就好了,使用方式就是在columns中定义一个type:selection的对象就行了。

const columns = [ {type:'selection'} ] 复制代码

那因为时间的关系,上文就先到这里啦,余下的操作项,分页其实按照以上的思路也不难做了,而这里,就在之后的下文中再详细说明吧! 告辞



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭