我报名参与金石方案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个,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-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办法,返回验证正确的数据。

功能问题

实际运用中,我发现这样封装好像有点卡,现在暂时不知道是哪里的问题,有待研讨