博客地址:https://ainyi.com/66html
又接到新需求了吧~~vue
在一个大表单里,有可能会出现这种需求,用户能够本身操做动态添加、移除表单,更加个性化的效果。
常见于填写我的信息、附加内容的表单数组
例如:
“工做经历”能够用户本身点击继续添加按钮,在原有的表单后面 append 多一个表单,不须要就点击右上方 X 按钮移除app
在实现以前,提出几个问题async
...
好吧,我当时也思考了一会,最后选择数组方式,动态渲染ui
利用数组,v-for 循环方式,能够完美实现动态渲染和移除,由于操做的只有对象数组而已this
请格外注意动态添加表单的 rule 和 prop编码
每一个动态添加的表单都要加上 rule
prop 须要根据对象数组下标绑定设置对应的 value(:prop="'azList[' + index + '].azName'")spa
<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 代码为code
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