博客地址: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. 设置yum源:

    1.企业    阿里开源镜像站:   http://mirrors.aliyun.com/ 搜狐开源镜像站: http://mirrors.sohu.com/ 网易开源镜像站: http://mirr ...

  2. 浅析ajax原理与用法

    1 ajax原理 Ajax(Asynchronous JavaScript and XML (异步的JavaScript和XML)),是一种快速创建 动态网页的技术,目的是显示动态局部刷新.通过XML ...

  3. Spring 系列之Spring常用注解总结

    传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.实物,这么做有两个缺点: 1.如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大:如果按需求分开.xml文 ...

  4. Docker 镜像之进阶篇

    笔者在<Docker 基础 : 镜像>一文中介绍了 docker 镜像的基本用法,本文我们来介绍 docker 镜像背后的技术原理. 什么是 docker 镜像 docker 镜像是一个只 ...

  5. windows粘贴板操作-自己的应用和windows右键互动

    一.粘贴板操作函数 BOOL OpenClipboard(HWND hWnd);参数 hWnd 是打开剪贴板的窗口句柄,成功返回TRUE,失败返回FALSE BOOL CloseClipboard() ...

  6. SpringBoot | 第六章:常用注解介绍及简单使用

    前言 之前几个章节,大部分都是算介绍springboot的一些外围配置,比如日志配置等.这章节开始,开始总结一些关于springboot的综合开发的知识点.由于SpringBoot本身是基于Sprin ...

  7. 海思Hi3559A/CV100 DDR4驱动配置手册

    Hi3559AV100 DDR4 驱动配置说明 1.1 Hi3559AV100 DDR4 CLK/AC 驱动配置方法 寄存器地址 DDR PHY0:0x1206d0bc DDR PHY1:0x1206 ...

  8. Android项目实战(五十四):zxing 生成二维码图片去除白色内边距的解决方案

    目录:zxing->encoding->EncodingHandler类 中修改 createQRCode方法 private static final int BLACK = 0xff0 ...

  9. 记录一些flutter学习网址

    字体图标生成 http://fluttericon.com/Flutter中文网 https://flutterchina.club Flutter官网 https://flutter.ioFlutt ...

  10. MIP 2016年终总结

    MIP 项目组成立至今已经有一年多的时间,在过去的一年里,感谢各位的关注. 1. MIP JS 迭代 MIP JS 运行环境是 MIP 页面和 MIP 组件运行的基石.在 2016 年 4 月,MIP ...