我报名参与金石方案1期应战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情”
最近在做一系列后台办理体系,其顶用的最多的便是表单和表格了。这儿讲一下我最近对表单封装的思考。
以下是我的规划思路以及详细完成,我运用的是vue3+element-plus,因而这个组件也是以这两个库为根底。
已上传npm www.npmjs.com/package/@we…
规划方针
装备化
咱们希望把表格的内容,验证规矩,乃至于表单的款式,格局都能更规矩化,装备化,这样后续咱们能够经过构造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个,key
,component
。key
其实便是你表单里数据的字段名,而component
则是你指定的修正组件,在这儿咱们能够直接运用字符串,但其实这儿能够经过vue的动态组件完成更灵活的运用,比方咱们换一个组件库的input组件
import { Input } from '@varlet/ui'
import '@varlet/ui/es/input/style/index.js'
const oneItem = { component: Input }
这时候,咱们就需求动态组件去烘托它,因而咱们能够这样写去烘托,当component是一个字符串,比方el-input
的时候,咱们烘托element
的input
组件,至于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-upload
v-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
办法,返回验证正确的数据。
功能问题
实际运用中,我发现这样封装好像有点卡,现在暂时不知道是哪里的问题,有待研讨