vue3 + element-plus el-form 绑定各类数据结构

546 阅读2分钟

代码仓库

vue3/src/page/element · 江海寄余生/vue3 demo - 码云 - 开源中国

注:

model 只能是对象,不能是数组,绑定数组校验会不生效

prop 对应 model 的名,一定要对上,不然不会触发

绑定普通对象

<template>
    <div class="customer-el-form">
        <el-form
            ref="formRef"
            :model="formData"
            :rules="formDataRules">
            <el-form-item
                label="组名"
                prop="group">
                <el-input v-model="formData.group" />
            </el-form-item>
            <el-form-item
                label="用户名"
                prop="name">
                <el-input v-model="formData.name" />
            </el-form-item>
            <el-form-item
                label="年龄"
                prop="age">
                <el-input v-model="formData.age" />
            </el-form-item>
        </el-form>
    </div>
</template><script setup lang="ts">
import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n';
​
const i18n = useI18n()
const formData = ref({
    group: '',
    name: '',
    age: '',
});
const formDataRules = computed(() => {
    return {
        group: {
            required: true,
            message: i18n.t('user.groupEmpty'),
            trigger: ['blur', 'change'],
        },
        name: {
            required: true,
            message: i18n.t('user.nameEmpty'),
            trigger: ['blur', 'change'],
        },
        age: {
            required: true,
            message: i18n.t('user.ageEmpty'),
            trigger: ['blur', 'change'],
        },
    };
});
</script>

绑定普通对象,对象中有数组,数组中的元素为动态添加

<template>
    <div class="customer-el-form">
        <el-form
            ref="formRef"
            :model="formData"
            :rules="formDataRules"
            :validate-on-rule-change="false"
            @validate="triggerValidate">
            <el-form-item
                label="组名"
                prop="group">
                <el-input v-model="formData.group" />
            </el-form-item>
            <div
                v-for="(person, personIndex) in formData.list"
                :key="personIndex">
                <el-form-item
                    label="用户名"
                    :prop="`list.${personIndex}.name`"
                    :rules="formDataRules.name">
                    <el-input v-model="person.name" />
                </el-form-item>
                <div v-if="personIndex !== formData.list.length - 1">------------------------</div>
            </div>
        </el-form>
        <button @click="addPerson">增加</button>
    </div>
</template>
​
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n';
​
const i18n = useI18n()
const formData = ref({
    group: '',
    list: [
        {
            name: '',
            age: null,
        },
    ],
});
​
// 使用 computed 在切换语言时会更新 formDataRules,重新触发校验,实现校验信息更新
// 可以通过设置 validate-on-rule-change 为 false, 关闭 rules 变化时触发校验
const formDataRules = computed(() => {
    return {
        group: {
            required: true,
            trigger: ['blur', 'change'],
            message: i18n.t('user.groupEmpty'),
        },
        name: {
            required: true,
            trigger: ['blur', 'change'],
            message: i18n.t('user.nameEmpty'),
        },
        age: {
            required: true,
            trigger: ['blur', 'change'],
            message: i18n.t('user.ageEmpty'),
        },
    };
});
​
// 动态添加数据
const addPerson = () => {
    formData.value.list.push({
        name: '',
        age: null,
    });
};
</script>

效果图:

el-form-实例1.png

绑定数组,数组中的元素为动态添加

<template>
    <div class="customer-el-form">
        <el-form
            ref="formRef"
            v-for="(person, personIndex) in formData"
            :key="personIndex"
            :model="person"
            :rules="rules"
        >
            <el-form-item label="用户名" :prop="name" :rules="rules.name">
                <el-input v-model="person.name" />
            </el-form-item>
            <el-form-item label="年龄" :prop="age" :rules="rules.age">
                <el-input v-model="person.age" />
            </el-form-item>
        </el-form>
        <button @click="addPerson">增加</button>
    </div>
</template><script setup lang="ts">
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n';
​
const i18n = useI18n()
const formData = ref([
    {
        name: '',
        age: null
    }
])
​
const rules = computed(() => {
    return {
        name: {
            required: true,
            trigger: ['blur', 'change'],
            message: i18n.t('user.nameEmpty')
        },
        age: {
            required: true,
            trigger: ['blur', 'change'],
            message: i18n.t('user.ageEmpty')
        }
    }
})
​
const addPerson = () => {
    formData.value.push({
        name: '',
        age: null
    })
}
</script>

效果图:

el-form-实例2.png

存在的问题:

上述示例代码如果将 validate-on-rule-change 设置为 false,然后通过 watch 监听语言切换时使用 formRef.value?.validate() 手动触发校验,会出现如下图所示的问题:

el-form-实例3.png 只有 rules 的 第一项的 message 是使用 i18n 获取 且 手动触发 formRef.value?.validate() 时才会出现,后面的其他表单项不会受影响;如果第一项使用的自定义校验,则不会出现这种情况,debugger 发现获取到的 message 都是正确的但是第一项的校验信息没有更新,目前暂时没有找到原因。暂时可以通过把第一项设置为一个无用的占位表单项并在页面隐藏到来解决,或第一项使用自定义校验方法,或者先清空校验再重新触发。

解决切换语言时校验信息更新问题

vue3 + element form 封装自定义 Hooks 以解决切换语言后国际化校验信息无法更新问题