博客地址:https://ainyi.com/66

又接到新需求了吧~~

背景

在一个大表单里,有可能会出现这种需求,用户可以自己操作动态添加、移除表单,更加个性化的效果。

常见于填写个人信息、附加内容的表单

例如:

“工作经历”可以用户自己点击继续添加按钮,在原有的表单后面 append 多一个表单,不需要就点击右上方 X 按钮移除

问题

在实现之前,提出几个问题

  1. vue 怎么动态渲染或移除表单上去
  2. v-model 怎么绑定动态添加表单的 value 值
  3. 动态新增的表单如何验证
  4. 动态表单怎么填写对应的 prop

...

好吧,我当时也思考了一会,最后选择数组方式,动态渲染

代码实现讲解

利用数组,v-for 循环方式,可以完美实现动态渲染和移除,因为操作的只有对象数组而已

请格外注意动态添加表单的 rule 和 prop

每个动态添加的表单都要加上 rule

prop 需要根据对象数组下标绑定设置对应的 value(:prop="'azList[' + index + '].azName'")

<div class="section-form" v-for="(item, index) in form.azList" :key="index">
<span v-if="isShowCloseBtn" class="close" @click="deleteItem(index)">
<i class="el-icon-close"></i>
</span>
<el-form-item label="可用区名称:"
:rules="[{ required: true, message: '可用区名称不能为空' }]"
:prop="'azList[' + index + '].azName'"
label-width="150px">
<el-input placeholder="请输入可用区名称" v-model="item.azName" :maxlength="30"></el-input>
</el-form-item>
<el-form-item label="逻辑可用区编码:"
:rules="[{ required: true, message: '逻辑可用区编码不能为空' }]"
label-width="150px"
:prop="'azList[' + index + '].logicCode'">
<el-input placeholder="请输入唯一ID" v-model="item.logicCode" :maxlength="30"></el-input>
</el-form-item>
<el-form-item label="物理可用区编码:"
:rules="[{ required: true, message: '物理可用区编码不能为空' }]"
label-width="150px"
:prop="'azList[' + index + '].physicCode'">
<el-input placeholder="请输入唯一ID" v-model="item.physicCode" :maxlength="30"></el-input>
</el-form-item>
</div>

那么对应的 js 代码为

export default {
name: 'vouchersDetail',
data() {
return {
form: {
regionName: '',
regionCode: '',
// 动态添加的对象数组
azList: [
{
azName: '',
logicCode: '',
physicCode: ''
}
]
}
}
},
computed: {
// 至少保留一个动态表单的开关
isShowCloseBtn() {
return this.form['azList'].length > 1
}
},
methods: {
addItem() {
// 点击添加表单的按钮,只需要将表单绑定的 value 作为对象 push 到对象数组
this.form['azList'].push({
azName: '',
logicCode: '',
physicCode: '',
weight: ''
})
},
deleteItem(index) {
// 点击移除表单的按钮,根据点击的当前 index 移除对象数组的元素
this.form['azList'].splice(index, 1)
},
goBack() {
window.history.back(-1)
}
}
}

更新

19号更新,分离组件方法,写法更简便,易维护,还可以将校验规则剥离出去

根据上面的方法 利用数组,v-for 循环方式

此次更新,关键在于,是父组件引用子组件的 template 循环

v-for 循环数组的 item 对象传入子组件 template

每个子组件的 form 的 :model = 传入的 item,也就不需要用到数组下标 index,每个子组件是独立的一个 form,也就是说,每个动态添加字段的校验规则可以剥离出去了

父组件

template 循环

<create-region
class="section-form"
ref="refCreateAz"
:infoData="item"
:indexNum="index"
:isShowCloseBtn="isShowCloseBtn"
v-for="(item, index) in form.azList"
:key="index"
@deleteItem="deleteItem">
</create-region>

js 与原来无差,只是多了引入子组件的 component

components: {
CreateRegion: () => import('@/views/region/models/CreateRegion')
}

子组件

<template>
<el-form :model="infoData" :rules="rulesAz" label-width="150px" ref="formAz">
<span v-if="isShowCloseBtn" class="close" @click="deleteItem">
<i class="el-icon-close"></i>
</span>
<el-form-item label="可用区名称:" prop="azName" label-width="150px">
<el-input placeholder="请输入可用区名称" v-model="infoData.azName" :maxlength="30"></el-input>
</el-form-item>
<el-form-item label="逻辑可用区编码:" label-width="150px" prop="logicCode">
<el-input placeholder="请输入唯一ID" v-model="infoData.logicCode" :maxlength="30"></el-input>
</el-form-item>
<el-form-item label="物理可用区编码:" label-width="150px" prop="physicCode">
<el-input placeholder="请输入唯一ID" v-model="infoData.physicCode" :maxlength="30"></el-input>
</el-form-item>
<el-form-item label="权重设置:" label-width="150px">
<el-input placeholder="请设置权重" v-model="infoData.weight"></el-input>
</el-form-item>
</el-form>
</template> <script>
import { ORGION_AZLIST_RULES } from '@/views/service/rules'
export default {
props: {
infoData: {
require: true
},
indexNum: {
type: Number
},
isShowCloseBtn: {
type: Boolean
}
},
data() {
return {
form: this.infoData,
rulesAz: ORGION_AZLIST_RULES.call(this)
}
},
computed: {},
methods: {
deleteItem() {
this.$emit('deleteItem', this.indexNum)
},
validates() {
return new Promise((resolve, reject) => {
this.$refs['formAz'].validate(async valid => {
if (valid) {
// 验证通过
resolve(true)
} else {
reject(false)
}
})
})
}
}
}
</script>

校验

export const ORGION_AZLIST_RULES = function() {
return {
logicCode: [
{
required: true,
message: '逻辑可用区编码不能为空',
trigger: 'blur'
},
{
validator: CHECK_AZEXITS_CODE.bind(this),
trigger: 'blur'
}
],
physicCode: [
{
required: true,
message: '物理可用区编码不能为空',
trigger: 'blur'
},
{
validator: CHECK_AZEXITS_CODE.bind(this),
trigger: 'blur'
}
],
azName: [
{
required: true,
message: '可用区名称不能为空',
trigger: 'blur'
}
]
}
}

自定义校验

export const CHECK_AZEXITS_CODE = async function(rule, value, callback) {
let paramName = rule.field
let reqData = {}
reqData[paramName] = value
let { result } = await getAzExist(reqData)
if (result.result) {
if (paramName === 'logicCode') {
callback(new Error('逻辑可用区编码已存在,请重新输入'))
} else {
callback(new Error('物理可用区编码已存在,请重新输入'))
}
} else {
callback()
}
}

写在后面

如果大家有啥更好的方法实现,欢迎在评论区相互探讨~

写完下班、

博客地址:https://ainyi.com/66

vue + element 动态渲染、移除表单并添加验证的更多相关文章

  1. v-if案例解析(element-ui form-item 结合 v-if 动态生成rule规则\表单元素,表单无法验证问题剖析 )

    fire 读在最前面: 1.此文章衔接Vue 虚拟Dom 及 部分生命周期初探,相关整体知识点请先阅读后再继续本文阅读 问:当v-if为true时,会重新渲染相关dom节点吗? <child v ...

  2. 如何在.Net Core MVC中为动态表单开启客户端验证

    非Core中的请参照: MVC的验证 jquery.validate.unobtrusive mvc验证jquery.unobtrusive-ajax 参照向动态表单增加验证 页面引入相关JS: &l ...

  3. vue同一页面中拥有两个表单时,验证问题

    问题:如果vue的同一个页面拥有两个表单.验证第一个表单时没有通过就切换到第二个,那么第二个表单会出现验证错误的信息 我们可以通过为两个表单添加ref属性 之后在通过调用resetFields()方法 ...

  4. 使用CSS来渲染HTML的表单元素

    效果: 实现: <!DOCTYPE html> <html> <head> <title>使用CSS来渲染HTML的表单元素</title> ...

  5. Element Ui使用技巧——Form表单的校验规则rules详细说明

    Element UI中对Form表单验证的使用介绍: Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item的 prop 属性设置为需校验的字段名 ...

  6. 第一百八十六节,jQuery,验证表单插件,Ajax 表单插件,验证和提交表单

    jQuery,验证表单插件,Ajax 表单插件,验证和提交表单 HTML <form id="reg" method="post" action=&quo ...

  7. 推荐几款很棒的 JavaScript 表单美化和验证插件

    表单元素让人爱恨交加.作为网页最重要的组成部分,表单几乎无处不在,从简单的邮件订阅.登陆注册到复杂的需要多页填写的信息提交功能,表单都让开发者花费了大量的时间和精力去处理,以期实现好用又漂亮的表单功能 ...

  8. form表单的ajax验证2

    form表单的ajax验证2: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"&g ...

  9. 在Tomcat中采用基于表单的安全验证

    .概述   (1)基于表单的验证 基于From的安全认证可以通过TomcatServer对Form表单中所提供的数据进行验证,基于表单的验证使系统开发者可以自定义用户的登陆页面和报错页面.这种验证方法 ...

随机推荐

  1. Spring IOC(三)依赖注入

    本系列目录: Spring IOC(一)概览 Spring IOC(二)容器初始化 Spring IOC(三)依赖注入 Spring IOC(四)总结 目录 1.AbstractBeanFactory ...

  2. cannot be cast to java.lang.Comparable

    Exception in thread "main" java.lang.ClassCastException: com.myradio.People cannot be cast ...

  3. RabbitMQ的介绍及使用进阶(Docker+.Net Core)

    目录: 一.什么是RabbitMQ 二.RabbitMQ运用场景 三.RabbitMQ优势及特点 四.Centos7中Docker安装RabbitMQ 五..Net Core 中使用RabbitMQ ...

  4. App 更换应用图标

    一般情况下,我们App图标在Androidmanifest.xml中设置,通过Application android:icon属性指定,写法如下: <?xml version="1.0 ...

  5. java基础( 九)-----深入分析Java的序列化与反序列化

    序列化是一种对象持久化的手段.普遍应用在网络传输.RMI等场景中.本文通过分析ArrayList的序列化来介绍Java序列化的相关内容.主要涉及到以下几个问题: 怎么实现Java的序列化 为什么实现了 ...

  6. java监听器简述

    监听器的概念 所谓监听器就是对内置对象的状态或者属性变化进行监听并且做出反应的特殊servlet,并且也需要在web.xml文件中进行相关配置. 内置对象的状态变化:初始化和销毁,也就是说当内置对象初 ...

  7. CentOS7中搭建cobbler自动装机服务

    一.实验环境 一台centos7 epel源网址 https://fedoraproject.org/wiki/EPEL?rd=Epel 使用nat模式 二.实验步骤 1.下载epel源后进行文件夹挂 ...

  8. iftop命令使用范例

    iftop 介绍 iftop是一款实时流量监控工具,监控TCP/IP连接等,缺点就是无报表功能.必须以root身份才能运行. 实例 默认是监控第一块网卡的流量 iftop 监控eth1 iftop - ...

  9. [转]webstorm中js文件被识别成txt类型

    问题描述: webstorm中index.js文件被识别成txt格式,如下图. 原因: webstorm中js文件被识别成txt文件,原因在于txt类型识别了以当前js文件名命名的模式. 解决办法: ...

  10. SqlServer中循环给多张表建立聚簇索引

    缘由 因为在某个复(bian)杂(tai)需求中用到了170+张表进行查询,而且表中的数据过多,查起来缓慢.只能给这些表添加索引.但是,连表名也是无法确定的(无力吐槽). 解决方法 使用游标遍历查询出 ...