基于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>