概述
场景介绍
某些情况下我们会遇到一些特殊的需求场景。
外面是个大表单:包含邮箱和对应的答案
答案这里是遍历出来的子表单,点击新增就新增一个分类答案
但是通用答案里 只有答案是必填的,选择区域是非必填
其他的分类答案里答案和选择区域都是必填的。
这里遍历的子表单的规则就有差异了,而且还是子表单,点击保存的时候我们是在父表单那里判断是否通过校验。
(tips: 对于大佬来说可能很简单,但是我第一次遇到这种需求,我原本的思路错了,导致我卡了三个小时,第二天早上来的时候才看着elementUI官网的form想出来怎么实现的)
rules.js
export const rules = {
email: [
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur'] }
],
answer: [
{required: true, message: '请输入答案', trigger: 'blur'},
{min: 1, max: 1000, message: '请输入 1 到 1000 个字', trigger: 'blur'},
],
region: [
{required: true, message: '请绑定客户标签', trigger: 'blur'},
]
};
Form1.vue // 父级表单
<template>
<el-form
ref="dynamicValidateForm"
:model="dynamicValidateForm"
class="demo-dynamic"
label-width="80px"
:rules="rules"
>
<el-form-item
prop="email"
label="邮箱"
>
<el-input v-model="dynamicValidateForm.email"></el-input>
</el-form-item>
<div class="answer-tab-container">
<span
v-for="(_item, index) in dynamicValidateForm.list"
:key="`list-${index}`"
:class="['list', index === activeAnswerIndex ? 'is-active' : '']"
@click="changeActiveAnswer(index)"
>
{{ index ? '分类答案' + index : '通用答案' }}
</span>
<el-button
type="text"
@click="addItem"
>
<span class="btn-text">
+ 新增
</span>
</el-button>
</div>
<answer-item
v-for="(item, index) in dynamicValidateForm.list"
v-show="index === activeAnswerIndex"
ref="answerRef"
:key="(item.id || item.key) + 'answer'"
:data="dynamicValidateForm"
:answer-item="item"
:current-index="index"
:is-last-answer="index === dynamicValidateForm.list.length - 1"
class="answer-editor"
@remove="removeItem"
/>
<div class="footer">
<el-button
type="primary"
@click="submitForm"
>
保存
</el-button>
<el-button>
取消
</el-button>
</div>
</el-form>
</template>
<script>
import AnswerItem from './components/AnswerItem';
import {rules} from './rules';
export default {
components: {
AnswerItem
},
data() {
return {
rules,
activeAnswerIndex: 0,
dynamicValidateForm: {
email: '',
list: [
{
answer: '',
key: Math.random(),
region: []
}
]
}
};
},
mounted() {
if (!this.dynamicValidateForm.list?.length) {
this.dynamicValidateForm.list = [];
this.addItem();
}
},
methods: {
/**
* 表单校验
* @param [forms='form'] 要校验的表单,可以是字符串或者ElForm实例或者带有validate校验方法的组件
* @param [callback] 校验表单后的回调函数,当传入该值时执行结果Promise一直为resolved
* @return Promise
*/
$validate(this, forms = 'forms', callback = null) {
if (typeof forms === 'function') {
callback = forms;
forms = '';
}
if (!(forms instanceof Array)) {
forms = [forms];
}
let newForms = forms.map(form => {
if (typeof form === 'string') {
return this.$refs[form || 'form'];
}
return form;
}).filter(v => v && v.validate);
let need_valid = newForms.length;
let in_valid = false;
return new Promise((resolve, reject) => {
function cb(valid, detail = null) {
need_valid -= 1;
if (in_valid) {
return;
}
if (typeof valid === 'undefined') {
valid = true;
}
if (valid && typeof valid !== 'boolean' && !detail) {
detail = valid;
valid = false;
}
if (!valid) {
console.warn('$validate', detail);
in_valid = true;
let error = new Error('数据校验失败,请检查填写内容');
if (typeof callback === 'function') {
callback(false, detail);
resolve(error);
}
else {
reject(error);
}
return;
}
if (need_valid === 0) {
if (typeof callback === 'function') {
callback(true);
}
resolve(true);
return;
}
}
// 放入下一帧执行,避免立即校验出错时浏览器 paused on promise rejection
this.$nextTick(() => {
newForms.forEach(form => form.validate(cb));
if (newForms.length === 0) {
need_valid = 1;
cb(true);
}
});
});
},
changeActiveAnswer(index) {
this.activeAnswerIndex = index;
},
addItem() {
const newItem = {
answer: '',
key: Math.random(),
tags: []
};
this.dynamicValidateForm.list.push(newItem);
this.changeActiveAnswer(this.dynamicValidateForm.list.length - 1);
},
removeItem(index) {
if (index === 0) {
return;
}
this.dynamicValidateForm.list.splice(index, 1);
this.changeActiveAnswer(index - 1);
},
async submitForm() {
try {
await this.$validate(this.$refs.dynamicValidateForm);
await Promise.all(
this.$refs.answerRef.map(
form => this.$validate(form.$refs.answerForm)
)
);
}
catch (e) {
console.log('e', e)
this.$message.warning('请正确填写后才能保存');
return;
}
this.$message.success('成功');
},
}
};
</script>
<style lang="less" scoped>
.demo-dynamic {
margin: 20px auto 0;
width: 800px;
.list {
border: 1px solid black;
&.is-active {
background-color: aqua;
}
}
}
</style>
AnswerItem.vue // 子表单
<template>
<el-form
v-if="data"
ref="answerForm"
:model="data"
label-width="90px"
>
<el-form-item
:label="'答案' + (currentIndex || '')"
:prop="'list.' + currentIndex + '.answer'"
:rules="rules.answer"
>
<el-input v-model="answerItem.answer"></el-input>
<el-button
v-if="currentIndex > 0"
type="text"
class="ml10"
@click="onRemove(currentIndex)"
>
删除
</el-button>
</el-form-item>
<el-form-item
:key="(answerItem.id || answerItem.key) + 'region'"
label="选择区域"
:prop="'list.' + currentIndex + '.region'"
:rules="currentIndex ? rules.region : {}"
>
<el-select v-model="answerItem.region" placeholder="请选择区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
</el-form>
</template>
<script>
import {rules} from '../rules';
export default {
props: {
data: {
type: Object,
default: null
},
answerItem: {
type: Object,
default: null
},
currentIndex: {
type: Number,
default: -1
}
},
data() {
return {
rules
};
},
mounted() {
},
methods: {
onRemove(index) {
this.$emit('remove', index);
}
}
};
</script>
<style lang="less" scoped>
</style>
因为答案这块我们是v-for 遍历出来的,所以我们的答案和选择区域对应的是 dynamicValidateForm.list 数组。因此我们可以给动态的给prop,
:prop="'list.' + currentIndex + '.answer'"
这样我们通用答案和分类答案都会对应数组中自己的位置。不过他们在哪都是必填的,所以rules就可以写死: rules=“rules.answer”
然后就是我们的选择区域,他这里通用答案和分类答案对应的规则就不一样了,所以这里的rules要给不同的
:rules="currentIndex ? rules.region : {}"
// 最简单的方法就是根据下标判断,currentIndex 为0 就表示是第一项 也就是通用答案 菲比条 所以给{}。 其余的都要求必填 就走 rules.region的规则就行
回到父组件这里,我们想要保存肯定要看里面的校验都通过没有
async submitForm() {
try {
await this.$validate(this.$refs.dynamicValidateForm);
await Promise.all(
this.$refs.dynamicValidateForm.map(
form => this.$validate(form.$refs.dynamicValidateForm)
)
);
}
catch (e) {
this.$message.warning('请正确填写后才能保存');
return;
}
// 校验都通过了 这里可以写想要执行的方法
this.$message.success('成功');
},
示例
这个问题记录一下,毕竟卡了我四个多小时加班到九点多也没整出来,第二天早上九点到了之后干了半小时干出来的。
这是我第一次见到 props也能动态赋值的,
还是根据数组的下标: 数组.下标.键名 这样动态赋值的
最后
以上就是开心皮带为你收集整理的遍历的子表单,对应的校验规则不同,父表单提交时的校验写法的全部内容,希望文章能够帮你解决遍历的子表单,对应的校验规则不同,父表单提交时的校验写法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复