头图

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个,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方法,返回验证正确的数据。
性能问题
实际使用中,我发现这样封装似乎有点卡,目前暂时不知道是哪里的问题,有待研究

10 声望
0 粉丝
0 条评论
推荐阅读
必知!这些软件测试的面试技巧,你必定用得上
对于面者来说如何顺利的通过面试,拿到心仪的offer,是大家最关心的,而面试,除了自身能力外,事先充分的准备也是十分有必要,所以以下这些软件测试的面试技巧,你要提前知道! 熟悉简历在面试之前一定要认真过...

视角线阅读 197

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木60阅读 6k评论 16

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs39阅读 6.2k评论 12

封面图
从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木39阅读 7.1k评论 6

CSS 绘制一只思否猫
欢迎关注我的公众号:前端侦探练习 CSS 有一个比较有趣的方式,就是发挥想象,绘制各式各样的图案,比如来绘制一只思否猫?思否猫,SegmentFault 思否的吉祥物,是一只独一无二、特立独行、热爱自由的(&gt;^ω^&lt...

XboxYan42阅读 2.8k评论 14

封面图
还在用 JS 做节流吗?CSS 也可以防止按钮重复点击
举个例子:一个保存按钮,为了避免重复提交或者服务器考虑,往往需要对点击行为做一定的限制,比如只允许每300ms提交一次,这时候我想大部分同学都会到网上直接拷贝一段throttle函数,或者直接引用lodash工具库

XboxYan34阅读 2.2k评论 2

封面图
从零搭建 Node.js 企业级 Web 服务器(二):校验
校验就是对输入条件的约束,避免无效的输入引起异常。Web 系统的用户输入主要为编辑与提交各类表单,一方面校验要做在编辑表单字段与提交的时候,另一方面接收表单的接口也要做足校验行为,通过前后端共同控制输...

乌柏木32阅读 6.1k评论 9

10 声望
0 粉丝
宣传栏