博客地址: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