需求比较简单就是验证一个表单,但是表单的项目是一个数组,每一个输入框都是v-for动态绑定的,其实和一个稳定的表单校验大部分要注意的点是一样的,只是一个问题prop的取值如何取比较复杂。
数据结构是这样的,routeTable中有俩个数组结构的子对象,而俩个数组中的元素结构又是一样的,而且业务逻辑也一样,所以将这两个数组分别传递给同一种子组件,并传递了key的句柄url-type。
routeTable = {
serviceUrl: [{
id: 1,
weight: 1,
url: 'http://'
}],
subscribeUrl: [{
id: 1,
weight: 1,
url: 'http://'
}]
}
调用子组件及向子组件传值,
<el-divider content-position="left">
<el-checkbox :checked="true" :disabled="true">
<span style="color: #0c93ff">业务地址列表</span>
</el-checkbox>
</el-divider>
<centring-appkey-route-url
ref="service"
:route-table="centringForm.routeTable"
:modifiable="modifiable"
url-type="serviceUrl"
@delRouteUrl="delRouteUrl"/>
<el-divider content-position="left">
<el-checkbox :checked="true" :disabled="true">
<span style="color: #0c93ff">订阅地址列表</span>
</el-checkbox>
</el-divider>
<centring-appkey-route-url
ref="subscribe"
:route-table="centringForm.routeTable"
:modifiable="modifiable"
url-type="subscribeUrl"
@delRouteUrl="delRouteUrl"/>
子组件代码
<template>
<div>
<el-form ref="routeUrlForm" :model="routeTable" size="mini" inline label-width="60px">
<div v-for="(item, index) in routeTable[urlType+'']" :key="index">
<el-row>
<el-col :span="4">
<el-form-item label="id" required>
<el-input :disabled="true" v-model="item.id" size="mini" style="width: 50px;"/>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item :prop="urlType + '.' +index + '.url'" :rules="routeUrlRules.url" label="url">
<el-input :disabled="!modifiable" v-model="item.url" size="mini" style="width: 260px;"/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="权重" required>
<el-input-number :disabled="!modifiable" v-model="item.weight" :min="1" size="mini" style="width: 80px;"/>
</el-form-item>
</el-col>
<el-col :span="4">
<el-button v-if="modifiable && routeTable.serviceUrl.length - 1 == index" type="primary" size="mini" @click="addUrl">添加</el-button>
<el-button v-if="modifiable && routeTable.serviceUrl.length > 1" size="mini" type="danger" @click="deleteUrl(index)">删除</el-button>
</el-col>
</el-row>
</div>
</el-form>
</div>
</template>
<script>
export default {
name: 'CentringAppkeyRouteUrl',
// eslint-disable-next-line vue/require-prop-types
props: ['routeTable', 'urlType', 'modifiable'],
data() {
var checkUrl = (rule, value, callback) => {
console.log(value)
// eslint-disable-next-line eqeqeq
if (value != null && value != '') {
var partten = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/
if (partten.test(value)) {
callback()
} else {
callback(new Error('请输入正确的url'))
}
} else {
callback(new Error('请输入url'))
}
}
return {
routeUrlRules: {
url: [{ validator: checkUrl, trigger: 'blur' }]
}
}
},
methods: {
// 删除按钮
deleteUrl(index) {
// eslint-disable-next-line eqeqeq
if (this.routeTable[this.urlType + ''][index].is_new == true) { // 是新加的,直接删
this.routeTable[this.urlType + ''].splice(index, 1)
} else { // 是已编排过的,删之前要判断是不是最后一个
var cnt = 0
this.routeTable[this.urlType + ''].forEach(item => { // 统计原有url个数
// eslint-disable-next-line eqeqeq
if (item.is_new != true) {
cnt += 1
}
})
if (cnt <= 1) {
this.$message.error('最后一个不可删除!') // 是最后一个,不做操作
} else {
this.$emit('delRouteUrl', { urlType: this.urlType, routeUrl: this.routeTable[urlType + ''][index] })
}
}
},
// 添加按钮
addUrl() {
var nextId = 0
this.routeTable[this.urlType + ''].forEach(item => { // 找最大id
if (item.id >= nextId) {
nextId = Number(item.id) + 1
}
})
this.routeTable[this.urlType + ''].push({
id: nextId,
weight: 1,
url: 'http://',
is_new: true // 手动添加标记
})
},
validate() {
this.$refs.routeTable[this.urlType + ''].Form.validate((valid) => {
alert(valid)
})
}
}
}
</script>
<style scoped>
</style>
其中要注意的有:
1.rules相关数据与一般的校验都一样
2.el-form中的model必须是一个Object类型,所以传递了routeTable这个对象。不带model参数整个表单都不会启动校验的。
3.最关键也是最复杂的prop的值定位,这个值是以model为根找起,我要找url就必须先找到他所在的数组,然后是数组的下标,最后定位到url,每一层级使用"."分隔开,最终就成了如下所示的写法。
:prop="urlType + '.' +index + '.url'"