vue element ui动态表单国际化问题解决方案

2021-06-10  本文已影响0人  码农梦醒

问题概述

基于element ui做了一个动态表单组件(根据配置,自动生成表单), 本来一切功能正常, 但由于项目需要支持国际化, 本来以为只是简单引入vue-i18n就行了, 没想到在国际化切换时, 表单的label, rule,placeholder并未同时切换

问题原因

自定义配置的label,placeholder和rule属性是纯粹的字符串和数组类型, 也就是说, 配置一旦创建, 实际上已经不具备自动响应式的能力. 那么解决方案就是让label, rule,placeholder能够在语言切换时, 进行自动响应, 从而重新生成对应值

网上找到的解决办法

方案一: 将rules或label等单独定义到computed中, 这样当国际化切换时, 会自动重新计算. 可行, 但会造成配置割裂, 原来的动态表单组件, 也会需要进行较大工作量的重构

方案二: 监听语言变更, 手动更新表单配置信息. 理论上也是可行的, 但会增加很多的编程量

这一刻陷入了僵局。难道就没有一个更好的方案?

想起以前做angular项目也需要国际化支持, 用的好像是ng-zero, 国际化切换时, ng-zero的表头, 并未跟着一起切换(那时也是通过配置方式生成表,表头名称字段也是定义的字符串). 后来将表头名称字段改成了函数, 问题解决。vue是不是也可以用这种方式? 想到就试试. 最后验证通过, 果然是可以的.

我的最终解决方案

将需要国际化支持的配置, 都改为即能传入Function又能传入字符串

简化代码如下:

SimpleForm

<template>
    <div>
        <el-form :model="ruleForm" ref="ruleForm" label-width="100px" :rules="realRules" class="demo-ruleForm"
                 v-if="editable">
            <el-form-item label="名称" prop="name">
                <el-input v-model="ruleForm.name"></el-input>
            </el-form-item>
            <el-form-item label="爱好" prop="hobby">
                <el-select v-model="ruleForm.hobby" placeholder="请选择">
                    <el-option
                            v-for="item in options"
                            :key="item.value"
                            :label="item.label"
                            :value="item.value">
                    </el-option>
                </el-select>
            </el-form-item>
        </el-form>
        <ul v-else>
            <li>名称:{{ruleForm.name}}</li>
            <li>爱好:{{ruleForm.hobby}}</li>
            <li>年龄:{{ruleForm.age}}</li>
        </ul>
    </div>
</template>

<script>
    export default {
        name: "SimpleForm",
        components: {},
        created() {
        },
        props: {
            editable: {
                type: Boolean,
                default: false
            },
            data: {
                type: Object,
                default: () => {
                    return {}
                }
            },
            rules: {
                type: Object,
                default: () => {
                    return {}
                }
            },
            options: {
                type: Array,
                default: () => {
                    return []
                }
            }
        },
        data() {
            return {
                ruleForm: {...this.data},
                // 最近的正确的表单数据
                lastFormData: {...this.data},
                realRules: {...this.rules},
                realOptions: []
            };
        },
        watch: {
            data(newVal) {
                console.log('data发生变化')
                this.ruleForm = {...newVal}
                this.lastFormData = {...newVal}
            },
            rules(newVal) {
                console.log('rules发生变化')
                this.realRules = {...newVal}
            },
            options(newVal) {
                console.log('options发生变化')
                this.realOptions = [...newVal]
            }
        },
        methods: {
            validateFormDataNotChange() {
                if (this.ruleForm.name === this.lastFormData.name && this.ruleForm.hobby === this.lastFormData.hobby) {
                    // 没改
                    return {notChanged: true};
                }
                // 改了
                return {notChanged: false, lastFormData: this.lastFormData};
            },
            submitForm(formName = 'ruleForm') {
                return new Promise((reslove) => {
                    this.$refs[formName].validate((valid) => {
                        if (valid) {
                            reslove(this.ruleForm)
                        } else {
                            console.log('error submit!!');
                            return false;
                        }
                    });
                })
            },
            resetForm(formName = 'ruleForm') {
                this.$refs[formName].resetFields();
            },
            handleCusEvt() {
                this.$refs['ruleForm'].validateField('org');
            }
        }
    }
</script>

<style scoped>

</style>

<template>
    <div class="hello">
        <el-button @click="editable=!editable">切换</el-button>
        <simple-form :data="data" :editable="editable" :field-config-arr="fieldConfigArr"></simple-form>
    </div>
</template>

<script>
    import SimpleForm from "@/components/SimpleForm";

    export default {
        name: "HelloWorld",
        components: {
            SimpleForm
        },
        props: {
            msg: String
        },
        data() {
            return {
                i18nMsg: {
                    i18nVal: () => this.$t('lang')
                },
                data: {},
                editable: true,
                fieldConfigArr: [
                    {
                        prop: 'name',
                        label: () => this.$t('name'),
                        rules: () => [{required: true, message: this.$t('mustInput'), trigger: 'blur'}],
                        placeholder: () => this.$t('placeholder')
                    },
                    {
                        prop: 'age',
                        label: this.$t('age'),
                        rules: [{required: true, message: this.$t('mustInput'), trigger: 'blur'}],
                        placeholder: this.$t('placeholder')
                    }
                ]
            }
        }
    };
</script>

<style scoped lang="scss">
</style>

上面的例子中, 姓名配置用的是Function, 年龄配置用的是字符串, 所以,姓名的相关信息, 是能完全支持国际化的, 年龄就不行了.

上一篇下一篇

猜你喜欢

热点阅读