我是靠谱客的博主 开心皮带,最近开发中收集的这篇文章主要介绍遍历的子表单,对应的校验规则不同,父表单提交时的校验写法,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

场景介绍

某些情况下我们会遇到一些特殊的需求场景。
外面是个大表单:包含邮箱和对应的答案
答案这里是遍历出来的子表单,点击新增就新增一个分类答案
但是通用答案里 只有答案是必填的,选择区域是非必填
其他的分类答案里答案和选择区域都是必填的。
这里遍历的子表单的规则就有差异了,而且还是子表单,点击保存的时候我们是在父表单那里判断是否通过校验。

(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也能动态赋值的,
还是根据数组的下标: 数组.下标.键名 这样动态赋值的

最后

以上就是开心皮带为你收集整理的遍历的子表单,对应的校验规则不同,父表单提交时的校验写法的全部内容,希望文章能够帮你解决遍历的子表单,对应的校验规则不同,父表单提交时的校验写法所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部