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

element的Form表单就应该这样用

设计目标

配置化

我们希望把表格的内容,验证规则,甚至于表单的样式,格式都能更规则化,配置化,这样后续我们可以通过构造json去实现一个表单,甚至可用实现拖拽式的构造表单。

参数简单

尽量减少json的层级,减少json的参数,字段更加语义化。

自由度

json其实是一套自由度的很少的规则,但是vue则我们提供更多的自由度,比如h函数,比如动态组件,利用这些方法我们可以实现更高的自由度。

我的实现过程

表单项的格式设计

首先第一步,我们先设计一个基础的格式,在这个JSON里,字段名都是很简单的英文单词,我专门把验证的规则rule放到每个子项里来,这也比较符合直观。

 const oneItem = {key: 'title',title: '小说名',component: 'el-input',props: { placeholder: '请输入姓名' },rule: [{ required: true, trigger: 'blur', message: '必填项' }],
} 

在这个格式里面,比较重要的主要是2个,keycomponentkey其实就是你表单里数据的字段名,而component则是你指定的编辑组件,在这里我们可以直接使用字符串,但其实这里可以通过vue的动态组件实现更灵活的应用,比如我们换一个组件库的input组件

import { Input } from '@varlet/ui' 
import '@varlet/ui/es/input/style/index.js'
const oneItem = {component:Input } 

这时候,我们就需要动态组件去渲染它,因此我们可以这样写去渲染,当component是一个字符串,比如el-input的时候,我们渲染elementinput组件,至于v-model这些我就省略了

<el-form-item v-for="item in items" :key="item.key"><el-input v-if="item.component === 'el-input'" /><component v-else :is="item.component" />
</el-form-item> 

v-bind的妙用

每个组件库的组件参数都不一样,而且有些属性我们可能并不使用,比如el-input有这个属性prefix-icon,是一个前缀图标,别的组件库不一定有啊,那到我们需要把所有组件库的所有属性都写在json? 我在之前的json中设计了以个props字段,这里面就是存放的是组件库的属性,或者是我们需要给组件传的值. 这时候,vue给我们提供了一个很方便的功能,直接使用v-bind传入一个对象,他就自动会帮我们把属性绑定。 比如这样写

const props = {a:1,b:2}
 <el-input v-if="item.component === 'el-input'" v-bind="props" /> 

vue就会自动处理为下面这种, 这就是v-bind的妙用。当然运用renderFunction也可以实现这个效果,诸君可以自己尝试一下

 <el-input v-if="item.component === 'el-input'" v-bind:a="props.a" v-bind:a="props.b"/> 

computed的妙用:实现v-model

下面我们来看一下数据的问题,vue中提供了方便v-model,方便我们修改的值能实时响应,并且我们可以自己实现一自定义v-model。 它的基本原理是这样,我们先父传子,然后子再通过事件告诉父组件修改这个值。大概实现就是这样

<script><button>+1</button>
</script>
export default{props:['modelValue', //v-model'a' //v-model:a],emits:['update:modelValue','update:a'],methods:{add(){this.$emit('update:modelValue',this.modelValue++)this.$emit('update:a',this.a++)}}
} 

但是这个代码里有一个问题,在vue中我们其实是无法修改props的,也就是说this.modelValue++会报错,那么如何解决这个问题呢,答案就是computed,computed其实也可以修改的,我们可以指定它的set方法,这样就躲避了修改props的问题,从而实现了v-model

{computed:{num:{get(){return this.modelValue},set(val){ this.$emit('update:modelValue',val)}}}
} 

useAttrs的妙用

在我的组件中有这样一个功能,上传。这就涉及到了回调函数的问题,也就是说我上传完,甚至包括方法的名字,这样才更灵活,比如我们在json中新增一个字段,

{
 uploader: { emits: 'handleUploadCover',
 }
} 

然后我在渲染的时候会给它绑上这个事件,那么我们如何获取到这个事件的函数,并调用呢?

<zForm @handleUploadCover="xxx" /> 

在vue3中,我使用了useAttrs,需要注意的是vue3这里似乎与vue2有些不同。vue3中,attrs获取到的是没有注册的值,比如你如果在emits里声明了,在这里就取不到了,不过这也正合我意,我们可以随意指定事件名。

const attrs = useAttrs()
/*返回值
 { onHandleUploadCover:function(){xxx}
 }
*/ 

可以看到这里能获取事件,只是名字略有不同,这里大家处理一下就行了

表单验证

表单里最重要的就是验证.首先在我之前的设计中,表单验证的规则是分布在每一个子项中,因此我们需要整合一下,这一块我就不赘述了,也很简单。

验证方法我是直接使用的el-form的验证,只是封装了一下罢了。 需要注意的是,如果你用的是script setup,需要使用defineExpose导出这个方法

const validate = ()=> new Promise((resolve) => {this.$refs.form.validate((isValid) => resolve(isValid));})
 defineExpose({ validate
 }) 

上传文件

上传文件这里我其实截取了一下element的上传,只使用了它选择的文件的功能,这块其实可以自己实现的。 因为我上传中间还要加很多参数,还有验证,因此我使用了before-upload方法,并主动reject.

 <el-uploadv-if="item.uploader"style="margin-top: 10px":before-upload="(file) => beforeUpload(file, item)":show-file-list="false"v-bind="item.uploader.props"><el-button type="primary">点击上传</el-button>
 </el-upload>
 const beforeUpload = (rawFile, { key, uploader }) => { /*执行逻辑,其实就是调起uploader.emits里的方法*/ return Promise.reject()
 } 

代码总结

我把demo放到了这里,后续有时间我整理一下发个npm包。 stackblitz.com/edit/vue-m8…

这次封装这个组件,我学到了很多东西,一些比较细微的vue3知识点,比如v-bind。但我也知道这也封装也有一些问题或者叫争论。

到底应不应该使用json

之前看过一篇封装el-table的文章,里面就反对使用json,原因无非2点:json结构过于庞大,json结构不利于接手代码的人使用。

  • 先说第二点,我觉得通过一个好的结构定义是可以缓解这个问题的,但是难道你函数式封装就没有学习成本了?我觉得json封装其实每次就是复制黏贴,反而学习成本更低,但是开发成本会更高,你需要处理各种错误的值,错误的结构,因此结构越简单越好,甚至可以拍平。* json并不庞大,庞大的是我们的表单,如果你表单里几百个条目,你怎么样写都只会庞大,因此还是建议分割表单,及时上报。需不需要v-model

在我这次封装中,我把数据通过v-model实时返回了,但是当我写到结尾的时候,我觉得表单的数据并不需要实时,因为我们需要的不是实时的数据,而是验证后的正确数据。因此我觉得我们可以暴露出一个getData方法,返回验证正确的数据。

性能问题

实际使用中,我发现这样封装似乎有点卡,目前暂时不知道是哪里的问题,有待研究

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

相关文章:

  • Linux基础组件之死锁检测
  • TypeScript——函数(函数定义类型、可选参数和默认参数、剩余参数、函数类型变量、使用接口封装函数变量类型)
  • T1056点和正方形的关系 (信息学一本通C++)
  • 【Selenium】一网打尽 小窗口滑动 全窗口滑动
  • 大数据必学Java基础(六十三):COW并发容器讲解
  • AutoCAD2014与致命的错误与独显直连
  • 联邦学习系列---读书个人总结
  • MyBatis概述、maven构建、Mapper接口及ORM思想
  • 【MyCat2】学习笔记(二)
  • 【洛谷题解/USACO题解】P2746 【USACO5.3】校园网Network of Schools
  • 防火墙iptables
  • Apiserver 执行顺序
  • Spring5 框架 ---- IOC容器(二)
  • Java面试题9.24
  • 【Visual Studio 2020】debug,release,配置属性,名词解释
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • Apache的80端口被占用以及访问时报错403
  • es6
  • JavaScript DOM 10 - 滚动
  • JS学习笔记——闭包
  • Vue.js-Day01
  • 排序算法之--选择排序
  • 使用 5W1H 写出高可读的 Git Commit Message
  • 世界上最简单的无等待算法(getAndIncrement)
  • 微信小程序:实现悬浮返回和分享按钮
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 正则学习笔记
  • 进程与线程(三)——进程/线程间通信
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​马来语翻译中文去哪比较好?
  • ​你们这样子,耽误我的工作进度怎么办?
  • #1015 : KMP算法
  • $().each和$.each的区别
  • (04)odoo视图操作
  • (2022 CVPR) Unbiased Teacher v2
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (阿里云万网)-域名注册购买实名流程
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (排序详解之 堆排序)
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • (五)MySQL的备份及恢复
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (译) 函数式 JS #1:简介
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .NET CF命令行调试器MDbg入门(一)
  • .Net Core 中间件验签
  • .NET MAUI学习笔记——2.构建第一个程序_初级篇