我是如何使用 vue2+element-ui 处理负责表单,避免单文件过大的问题
引言
在工作中我经常需要处理一些复杂、动态表单,但是随着需求不断迭代,我们也许会发现曾经两三百行的.vue文件现在不知不觉到了两千行,三千行,甚至更多...
这对于一个需要长期维护的项目,无疑是增加了很多难度。
因此,为了减小文件大小,优化表单组织的结构,我在日常的开发中实践出一种基于组件的表单拆分方法,同时还能保证所有的表单项是处于同一个el-form中。
这对于一个一开始就没有做好文件组织,组件化的项目,有以下几个优点:
- 改动小!后续新增表单项基本不会改动以前的代码
- 基于组件!在逻辑上对表单项做出拆分,并在任何地方嵌入
- 易维护!化单个大组件为多个小组件,每个组件只专注于一部分表单。
表单拆分
接下来我们会通过完成一个实际表单的方式来介绍如何实践这种表单组织方式。
以element-ui文档中的这个表单为例,接下来尝试用我们的方式来实现
首先假设我们当前有一个vue文件 ./form/myForm.vue
<template>
<el-form ref="form" :model="form" label-width="140px">
...
</el-form>
<template>
<script>
export default {
name: 'myForm',
data() {
return {
form: {}
}
}
}
</script>
如果我们直接按照element-ui的表单文档来写,那么我们的myForm.vue文件可能就会变成这样:
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="form.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="form.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="form.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="特殊资源">
<el-radio-group v-model="form.resource">
<el-radio label="线上品牌商赞助"></el-radio>
<el-radio label="线下场地免费"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="活动形式">
<el-input type="textarea" v-model="form.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
}
},
methods: {
onSubmit() {
console.log('submit!');
}
}
}
</script>
假设我们还需要为这个表单增加审批流程,例如文档中的这个表单
在加入新的表单项后,可能目前看着还好,但是随着表单项越来越多,这个文件会变得越来越大,越来越难以维护。所以我们尝试将这个表单项拆分为单个组件,模拟我们维护一个超大表单的场景。
新增子表单项组件
我习惯在当前表单的目录下,创建一个components目录,然后在components目录下创建一个audit目录,并在audit目录下创建一个index.vue文件,用于存放审批流程相关的组件。如果后续有一些只有audit/index.vue文件中才用到的组件,我也会放在audit目录下。保持目录结构清晰。
<template>
<div class="audit-form-item">
<el-form-item label="审批人" :prop="`${propPrefix}.user`">
<el-input v-model="form.user" placeholder="审批人"></el-input>
</el-form-item>
<el-form-item label="活动区域" :prop="`${propPrefix}.region`">
<el-select v-model="form.region" placeholder="活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
</div>
</template>
<script>
export const auditFormData = () => ({
user: '',
region: ''
})
export default {
name: 'auditFormItem',
props: {
value: {
type: Object,
default: () => auditFormData()
},
propPrefix: {
type: String,
default: ''
}
},
data() {
return {
form: this.value
}
},
watch: {
value(newVal) {
this.form = newVal
},
form(newVal) {
this.$emit('input', newVal)
}
}
}
</script>
因为element-ui在对表单进行校验时,实际上是对model上绑定的数据进行校验,所以为了能够对数据正确执行校验,我们需要在auditFormItem组件中实现v-model指令。
auditFormItem组件的propPrefix属性用于指定表单项的前缀,便于我们在嵌入到el-form中时,能够正确绑定表单项的prop属性。
auditFormData函数返回了当前表单项的默认数据。父组件通过执行该函数,可以对子表单执行正确的初始化。不仅如此,通过这种方式,我们将每个子表单项的数据和组件绑定在一起,避免了父组件data中出现大量表单项数据,导致难以维护的问题。每个子表单维护各自的数据,互不干扰。
如何嵌入已有项目
接下来我们尝试将auditFormItem组件嵌入到myForm.vue文件中
<template>
<el-form ref="form" :model="form" label-width="140px">
<!-- 其他表单项 -->
<!-- ... -->
<audit-form-item v-model="form.audit" propPrefix="audit"></audit-form-item>
</el-form>
</template>
<script>
import auditFormItem, { auditFormData } from './components/audit/index.vue'
export default {
components: {
auditFormItem
},
data() {
return {
form: {
audit: auditFormData()
}
}
}
}
</script>
如何进行校验
经过上面的操作,我们实现了将一个表单拆分为多个子表单项,那么如何进行表单校验呢?
我们知道在element-ui中,要对一个表单项进行校验有两种方式:
一种是在el-form上绑定rules属性,它会通过prop进行索引,自动对绑定的表单项进行校验。
另一种是在el-form-item上绑定rules属性,这会对单条表单项进行校验。
出于我们拆分表单项的场景,我们选择第二种方式,在el-form-item上绑定rules属性,然后在各个子组件中维护rules。如果有一些通用的校验规则,我们也可以在audit/validate.js文件中进行维护,然后通过import的方式引入。
如何处理联动校验
在复杂表单中,我们可能需要对多个表单项进行联动校验,例如:实时校验表单项的合法性,当form.region为shanghai时,form.user不能为空,当form.region为beijing时,form.user必须为空。
那么如何处理这种联动校验呢?
我们可以在el-form所在的组件中,定义一个validate方法,通过element-ui提供的validateField方法,对特定进行校验。
<audit-form-item v-model="form.audit" propPrefix="audit" @validate="validate"></audit-form-item>
methods: {
validate(fields) {
this.$refs.form.validateField(fields)
}
}
然后在audit/index.vue文件中,我们可以通过$emit('validate', fields)方法,对当前表单项进行校验。
如何处理跨组件的联动校验
在我们拆分表单为多个子组件后,还可能会出现不同子组件之间的联动校验,例如:当子组件1中的form.region为shanghai时,子组件2中的form.user不能为空。
对于这个问题,其实我目前还没有想到很好的解决方案,当前是在el-form所在的组件中,定义额外的校验规则,然后绑定到一个空白的el-form-item上。
<el-form-item label="" label-width="0" prop="_form_validate_"></el-form-item>
rules: {
_form_validate_: {
validator: (rule, value, callback) => {
// 联动校验逻辑
}
}
}
也可以考虑用vuex来维护需要跨组件共享的数据。
const crossCmpConfig = {
state: {
region: '',
},
mutations: {
UPDATE: (state, { key, val }) => {
state[key] = val
},
},
}
export default crossCmpConfig
多层嵌套
基于上面的方式,很容易就能想到,我们甚至可以继续在audit/index.vue文件中,继续嵌入别的子组件,例如:audit/audit-info/index.vue, 然后通过相同的方式,继续嵌入到audit/index.vue文件中。
结语
上面就是我日常开发中,处理复杂表单的一些经验总结,希望对大家有所帮助。
我是如何使用 vue2+element-ui 处理负责表单,避免单文件过大的问题的更多相关文章
- vue2.0+Element UI 实现动态表单(点击按钮增删一排输入框)
对于动态增减表单项,Element UI 官方文档表单那一节已经介绍得很清楚了,我之前没有看见,绕了很多弯路,这里针对点击按钮增删一排输入框的问题做一个总结. 效果图如下 存在一排必填的姓名与手机号, ...
- Element ui 中的表单提交按钮多次点击bug修复
- vue 使用 element ui动态添加表单
html部分 <div class="hello"> <el-form :model="dynamicValidateForm" ref=&q ...
- element ui动态生成表单数据与校验(后台传入数据)
前言 最近有一个需求是通过后台返回的数据,生成表单并添加校验.在做的过程中,动态表单挺好做,关键是校验.困扰了我2天,最后通过查找资料和"运气"终于解决了.解决问题关键点:vue的 ...
- element ui form表单清空规则
公司项目重构,经过商定使用element ui.在重构项目的时候发现一下element ui上很蛋疼的东西. 例如,这个form表单就是一个.趁着在高铁上没事,把想写的东西写一下. 先说一下eleme ...
- vue+element ui中select组件选择失效问题原因与解决方法
codejing 2020-07-10 09:13:31 652 收藏 分类专栏: Web Vue Element UI 版权 .当表单form赋完值后,如果后续又对form中某一属性值进行操作如 ...
- vue2.0 + Element UI + axios实现表格分页
注:本文分页组件用原生 html + css 实现,element-ui里有专门的分页组件可以不用自己写,详情见另一篇博客:https://www.cnblogs.com/zdd2017/p/1115 ...
- vue2.0 + element ui 实现表格穿梭框
element ui 官网里介绍了穿梭框(Transfer),但在实际使用过程中,会出现一些问题: 1.穿梭框里能放置的内容太少,不能满足复杂的业务需求. 2.当选项过多时,穿梭框很难实现分页,左右两 ...
- vue2.0+Element UI 表格前端分页和后端分页
之前写过一篇博客,当时对element ui框架还不太了解,分页组件用 html + css 自己写的,比较麻烦,而且只提到了后端分页 (见 https://www.cnblogs.com/zdd20 ...
- vue3的学习笔记:MVC、Vue3概要、模板、数据绑定、用Vue3 + element ui、react框架实现购物车案例
一.前端MVC概要 1.1.库与框架的区别 框架是一个软件的半成品,在全局范围内给了大的约束.库是工具,在单点上给我们提供功能.框架是依赖库的.Vue是框架而jQuery则是库. 1.2.MVC(Mo ...
随机推荐
- Go1.13的坑:无法结束Goroutine
背景 本人作为一名SRE,想用Go模拟Cpu占用100% 1秒钟,但是在Go1.13上遇到了问题,1s后Goroutine不会停止. 只要用了for{},Goroutine就无法结束,即使主Gorou ...
- 11-Python网络编程
socket包介绍 Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯. 创建一个T ...
- 浮点数格式:FP64, FP32, FP16, BFLOAT16, TF32之间的相互区别
浮点数格式 (参考1,参考2) 浮点数是一种用二进制表示的实数,它由三个部分组成:sign(符号位).exponent(指数位)和fraction(小数位).不同的浮点数格式有不同的位数分配给这三个部 ...
- 高通Android UEFI中的LCD分析(2):关键的函数
# 高通Android UEFI中的LCD分析(2):关键的函数 背景 在启动流程分析中,看到了几个经常出现的函数,这里实际分析一下有关的实现.以搞清楚高通做了什么,以及我们能做什么. 重要函数 MD ...
- Java 把多个音频拼接成一个
在Java中,将多个音频文件拼接成一个通常需要使用一些专门的音频处理库,因为Java标准库并不直接支持音频文件的合并.一个常用的库是JAVE2(Java Audio Video Encoder)或JL ...
- 国芯新作 | 四核Cortex-A53@1.4GHz,仅168元起?含税?哇!!!
获取更多T507全国产平台资料可在评论区留言或关注官方公众号~
- scala偏函数小栗子
package cn.beicaiqm.scala.day04 /** * Created by Administrator on 2018/6/1. * 被包在花括号内没有match的一组case语 ...
- OpenWrt中的LuCi和Lua一些总结
Lua.LuCi Lua是一种小巧的脚本语言,和Python一样,Lua脚本的运行需要Lua解释器: UCI(Unified Configuration Interface)是OpenWrt实现所有系 ...
- mysql 授权远程连接
解决方案 改表法 可能是你的帐号不允许从远程登陆,只能在localhost.这个时候只要在localhost的那台电脑,登入mysql后,更改 "mysql" 数据库里的 &quo ...
- 使用C#/.NET解析Wiki百科数据实现获取历史上的今天
创建一个webapi项目做测试使用. 创建新控制器,搭建一个基础框架,包括获取当天日期.wiki的请求地址等 创建一个Http请求帮助类以及方法,用于获取指定URL的信息 使用http请求访问 ...