基于vue2.x 和element-ui 动态生成表单项并添加表单校验;
1、需求问题
如下图,项目有个需求,点击添加按钮,新增一行设备信息,且每项信息必填;
2、代码
看到这个需求,首先想到要使用v-for的形式进行处理每一行设备信息;但是,之前没有搞过动态生成表单项并添加表单校验(最近几年又回归iOS开发,H5开发只是临时协助其他部门开发),自己先尝试写了下,但是表单校验死活不起作用;问了部门H5大佬,结果都是没有写过类似页面,怎么办,网上搜索呗;果然网上不少内容,但是在我项目中依旧是表单校验不起作用,只好一一尝试修改,最终搞定;
特别需要注意的一点是,想要其作用,不能直接给el-form
直接添加rules
,动态绑定,需要给具体el-form-item
添加对应的rules
;
有效代码示例:
<el-form ref="form" v-loading="isLoading" class="list-container" :model="form" label-width="0"><div v-for="(item, index) in form.devices" :key="index" class="list-item-container"><el-form-item :prop="'devices.' + index + '.name'" :rules="rules.name"><el-input v-model="item.name" class="list-item-input" size="small" maxlength="20" clearable placeholder="设备名称" /></el-form-item><el-form-item :prop="'devices.' + index + '.quantity'" :rules="rules.quantity"><el-input v-model="item.quantity" class="list-item-input-samll" size="small" maxlength="20" clearable placeholder="设备数量" /></el-form-item><el-form-item><el-button class="danger" size="small" type="text" @click="handleDelete(index)">删除</el-button></el-form-item></div></el-form>
无效代码示例:
<el-form ref="form" v-loading="isLoading" class="list-container" :model="form" :rules="rules" label-width="0"><div v-for="(item, index) in form.devices" :key="index" class="list-item-container"><el-form-item :prop="'devices.' + index + '.name'"><el-input v-model="item.name" class="list-item-input" size="small" maxlength="20" clearable placeholder="设备名称" /></el-form-item><el-form-item :prop="'devices.' + index + '.quantity'"><el-input v-model="item.quantity" class="list-item-input-samll" size="small" maxlength="20" clearable placeholder="设备数量" /></el-form-item><el-form-item><el-button class="danger" size="small" type="text" @click="handleDelete(index)">删除</el-button></el-form-item></div></el-form>
废话少数,直接上成品代码;
<template><div class="ledger-tab-page"><el-button type="primary" @click="handleAdd">{{ '添加' }}</el-button><el-form ref="form" v-loading="isLoading" class="list-container" :model="form" label-width="0"><div v-for="(item, index) in form.devices" :key="index" class="list-item-container"><el-form-item :prop="'devices.' + index + '.name'" :rules="rules.name"><el-input v-model="item.name" class="list-item-input" size="small" maxlength="20" clearable placeholder="设备名称" /></el-form-item><el-form-item :prop="'devices.' + index + '.quantity'" :rules="rules.quantity"><el-input v-model="item.quantity" class="list-item-input-samll" size="small" maxlength="20" clearable placeholder="设备数量" /></el-form-item><el-form-item :prop="'devices.' + index + '.km_mileage'" :rules="rules.km_mileage"><span class="list-item-text">DK</span><el-input v-model="item.km_mileage" class="list-item-input-samll" size="small" maxlength="3" clearable placeholder="安装里程" /></el-form-item><el-form-item :prop="'devices.' + index + '.metre_mileage'" :rules="rules.metre_mileage"><span> + </span><el-input v-model="item.metre_mileage" class="list-item-input-samll" size="small" maxlength="3" clearable placeholder="安装里程" /></el-form-item><el-form-item :prop="'devices.' + index + '.validity_date'" :rules="rules.validity_date"><el-date-picker v-model="item.validity_date" type="datetime" size="small" class="list-item-date" placeholder="请选择有效期" default-time="00:00:00" /></el-form-item><el-form-item><el-button class="danger" size="small" type="text" @click="handleDelete(index)">删除</el-button></el-form-item></div></el-form></div>
</template>
<script>import _ from 'lodash'export default {components: {BwtButton},props: {info: {type: Array,default: () => {return []}}},data() {return {isLoading: false,form: {devices: []},rules: {// 'devices.*.name': [// { required: true, message: '设备名称为必填项', trigger: 'blur' }// ],name: [{ required: true, message: '设备名称为必填项', trigger: 'blur' }],quantity: [{ required: true, message: '设备数量为必填项', trigger: 'blur' },{ type: 'number', message: '设备数量必须为数字', trigger: 'blur' },{ pattern: /^[1-9]\d{0,3}$/, message: '请输入正确的设备数量', trigger: 'blur' }],km_mileage: [{ required: true, message: '安装里程为必填项', trigger: 'blur' },{ type: 'number', message: '安装里程必须为数字', trigger: 'blur' },{ pattern: /^[1-9]\d{0,2}$/, message: '请输入正确的里程范围', trigger: 'blur' }],metre_mileage: [{ required: true, message: '安装里程为必填项', trigger: 'blur' },{ type: 'number', message: '安装里程必须为数字', trigger: 'blur' },{ pattern: /^[1-9]\d{0,2}$/, message: '请输入正确的里程范围', trigger: 'blur' }],validity_date: [{ required: true, message: '请选择有效期', trigger: 'blur' }]}}},computed: {},watch: {'info': function(newVal) {if (newVal) {// 处理详情回显this.form.devices = newVal || []}}},mounted() {},methods: {// 清空表单内容(供外部调用)resetFields() {this.form.devices = []},// 表单校验(供外部调用)formValidate() {// 校验:如果name为空,不允许提交return new Promise((resolve, reject) => {try {this.$refs.form.validate((valid) => {if (!valid) {this.$message.error('请完善设备信息')}resolve(valid)})} catch (error) {reject(error)}})},// 获取当前页面的表单数据formData() {return _.cloneDeep(this.form.devices)},// 新增handleAdd() {// 增加一行,const item = {name: '',quantity: '',km_mileage: '',metre_mileage: '',validity_date: ''}this.form.devices.push(item)},// 删除handleDelete(index) {this.form.devices.splice(index, 1)}}
}
</script>
<style scoped lang="scss">
.ledger-tab-page {margin: 20px 0;width: 100%;
}.list-container {margin-top: 10px;max-height: 400px;overflow-y: auto !important;
}.list-item-container {display: flex;width: 100%;
}.list-item-input {width: 200px !important;margin-right: 10px;
}.list-item-text {margin: 0 5px;
}.list-item-input-samll {width: 100px !important;margin-right: 5px;margin-left: 5px;
}.list-item-date {width: 200px !important;margin-right: 10px;
}</style>