我是如何使用 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 ...
随机推荐
- hdu4135题解 容斥
Problem Description Given a number N, you are asked to count the number of integers between A and B ...
- Controller-runtime模块
Controller-runtime框架 Controller-runtime是社区提供的用于开发Controller的框架,包含了各种已封装的代码库.Kubebuilder与Operator SDK ...
- W5100 硬件协议栈 调试经验
--- title: W5100 硬件协议栈 调试经验 date: 2020-06-21 11:22:33 categories: tags: - debug - tcpip - w5100 - su ...
- Linux 进程运行状态
背景: 以下有关的知识点是在多进程拷贝的时候,执行了sync导致卡死导致的. Linux进程状态:R (TASK_RUNNING),可执行状态.只有在该状态的进程才可能在CPU上运行.而同一时刻可能有 ...
- SqlCel 和MySQL for Excel在批量处理数据上的优劣
先放MySQL for Excel编辑数据的界面, 理论上可以批量修改数据....但是: 百度翻译如下: 更改不被允许.....[经测试,64位的Excel出现同样的情况] 转换思路:不使用公式去匹配 ...
- BZOJ 1461 题解
考虑设计一个哈希函数 \(hash(x) = f(x) \times base^x\). 其中 \(f(x)\) 表示 \(\sum_{j=1}^{i-1} [j <i]\). 然后类似于滑动窗 ...
- 机器学习策略篇:详解数据分布不匹配时,偏差与方差的分析(Bias and Variance with mismatched data distributions)
详解数据分布不匹配时,偏差与方差的分析 估计学习算法的偏差和方差真的可以帮确定接下来应该优先做的方向,但是,当训练集来自和开发集.测试集不同分布时,分析偏差和方差的方式可能不一样,来看为什么. 继续用 ...
- IstioCon 回顾 | 网易数帆的 Istio 推送性能优化经验
在 IstioCon2022 上,网易数帆资深架构师方志恒从企业生产落地实践的视角分享了多年 Istio 实践经验,介绍了 Istio 数据模型,xDS 和 Istio 推送的关系,网易数帆遇到的性能 ...
- 判断浏览器是否是 IE 及 IE8 以下版本
作为一个前端,避免不了会遇见IE的坑,其他浏览器都好好的,测到IE就完蛋,各种不支持,服气了 有些属性和方法是所有版本IE都不支持,而有些则是部分支持,在项目中能够,主要分界岭为IE8,我相信目前大部 ...
- c++ 17 demo
1 // Cpp.cpp : 此文件包含 "main" 函数.程序执行将在此处开始并结束. 2 // 3 4 #include <iostream> 5 #includ ...