博客地址: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. SAP GUI个性化设置

    大概从GUI730开始,GUI品牌化一直不被默认支持,在GUI设置选项里处于灰色状态,如下图: 不过用户还是可以修改注册表的方式来进行修改,让它可以设置! 首先运行Regedit,在目录:HKEY_L ...

  2. 理解图像分割中的卷积(Understand Convolution for Semantic Segmentation)

    以最佳的101 layer的ResNet-DUC为基础,添加HDC,实验探究了几种变体: 无扩张卷积(no dilation):对于所有包含扩张卷积,设置r=1r=1 扩张卷积(dilation Co ...

  3. 基于Java实现红黑树的基本操作

    首先,在阅读文章之前,我希望读者对二叉树有一定的了解,因为红黑树的本质就是一颗二叉树.所以本篇博客中不在将二叉树的增删查的基本操作了,需要了解的同学可以到我之前写的一篇关于二叉树基本操作的博客:htt ...

  4. ASP.Net Core MVC 发生二次请求

    Bug回忆录 昨天搭建新框架的时候,遇到一个很奇怪的“Bug”,每次请求都会触发两次Aciton,举例子吧,Demo: _Layout.cshtml <!DOCTYPE html> < ...

  5. GopherChina第一天小结

    GopherChina第一天小结 今天参加了Asta举办的第五届GopherChina,第一天参加完,颇有感受,晚上回来趁着还有记忆,来做一下记录. 写在前面 一早从9点开始,一天下来一共八个主题,各 ...

  6. slice是什么时候决定要扩张?

    slice是什么时候决定要扩张? 网上说slice的文章已经很多了,大都已经把slice的内存扩张原理都说清楚了.但是是如何判断slice是否需要扩张这个点却没有说的很清楚.想当然的我会觉得这个app ...

  7. 面试挂在了 LRU 缓存算法设计上

    好吧,有人可能觉得我标题党了,但我想告诉你们的是,前阵子面试确实挂在了 RLU 缓存算法的设计上了.当时做题的时候,自己想的太多了,感觉设计一个 LRU(Least recently used) 缓存 ...

  8. 结合JDK源码看设计模式——单例模式

    定义: 保证一个类仅有一个实例,并提供一个全局访问点 适用场景: 确保任何情况下这个对象只有一个实例 详解: 私有构造器 单利模式中的线程安全+延时加载 序列化和反序列化安全, 防止反射攻击 结合JD ...

  9. Angular(02)-- Angular-CLI命令

    声明 本系列文章内容梳理自以下来源: Angular 官方中文版教程 官方的教程,其实已经很详细且易懂,这里再次梳理的目的在于复习和巩固相关知识点,刚开始接触学习 Angular 的还是建议以官网为主 ...

  10. Github排序(转载)

    目录 1. 冒泡排序 2. 选择排序 3. 插入排序 4. 希尔排序 5. 归并排序 6. 快速排序 7. 堆排序 8. 计数排序 9. 桶排序 10. 基数排序 参考:https://mp.weix ...