vue+element UI+vue-i18n 页面多语言和表单验证优化

最近在踩vue的坑,记录一下自己项目中使用的总结。

版本说明

本文中使用模块版本如下,不保证代码对其他版本的适用。
vue: 2.5.2
element-ui: 2.4.11
vue-i18n: 8.8.0
lodash: 4.17.11

1. 多语言

使用vue-i18n对项目进行国际化,

1. npm安装

npm i --save-dev vue-i18n

2. 项目中添加语言包


语言包写法可类似如下格式

1
2
3
4
5
6
7
8
9
10
export const lang = {
user: {
login: '登录',
username: '用户名',
password: '密码',
registerInfo: '还没有账号?点击注册',
loginInfo: '欢迎!',
register: '注册账号',
},
};

3. 全局引入

在main.js文件中引入模块,并在页面初始化时默认使用中文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import VueI18n from 'vue-i18n'
Vue.use(VueI18n);

const DEFAULT_LANG = 'zh-CN';
const i18n = new VueI18n({
locale: DEFAULT_LANG,
messages: {
'zh-CN': require('./lang/zh'),
'en-US': require('./lang/en')
}
});

new Vue({
el: '#app',
router,
store,
i18n,
components: { App },
template: '<App/>'
});

4. 使用多语言语言包

  • html页面中直接引用:

    1
    <h1 class="text-center">{{$t('lang.user.loginInfo')}}</h1>
  • html页面中使用v-bind方法引用:

    1
    2
    3
     <el-input v-model="loginForm.username" :placeholder="$t('lang.user.username')" class="with-icon-input">
    <i class="fa fa-user" slot="prefix" style="margin-left:5px"></i>
    </el-input>
  • js页面中引用:

    1
    this.$i18n.t('lang.form.userName')

5. 切换语言

在header导航栏初始化时检测浏览器localStorage中是否存有lang数据,若没有,则默认初始化为中文。并在页面中添加切换语言的方法。

1
2
3
4
5
6
7
<template>
<el-submenu index="6" class="header-nav-item" style="float:right">
<template slot="title"><i class="fa fa-language"><span>{{$t('lang.nav.lang')}}</span></i></template>
<el-menu-item index="6-1" @click="changeLang('zh')">中文</el-menu-item>
<el-menu-item index="6-2" @click="changeLang('en')">English</el-menu-item>
</el-submenu>
</template>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
export default {
name: "HeadNav",
data() {
return {}
},
mounted() {
if (!window.localStorage.getItem('lang')) {
window.localStorage.setItem('lang', 'zh-CN');
this.$i18n.locale = 'zh-CN'
} else {
this.$i18n.locale = window.localStorage.getItem('lang')
}
},
methods: {
changeLang: function (lang) {
if (lang === 'zh') {
window.localStorage.setItem('lang', 'zh-CN')
this.$i18n.locale = 'zh-CN'
} else if (lang === 'en') {
window.localStorage.setItem('lang', 'en-US')
this.$i18n.locale = 'en-US'
}
}
}
}

2. 表单验证封装

element UI使用的表单验证框架为async-validator,所以可以参考文档直接将多个组件共用的表单验证封装为一个js文件。
formValid.js:

1
2
3
4
5
6
7
8
9
export default {
text : (rule, value, callback) => {
if (!value) {
return callback(new Error('不能为空'));
}else {
callback()
}
}
}

  • 全局引入:
1
2
import formValid from './config/formValid'
Vue.prototype.formValid = formValid;

此时可以直接在vue文件中直接使用this.formValid指向表单验证。

  • 单页面引入:
1
import formValid from '../config/formValid'

此时使用则不需要this,可直接使用formValid。

使用封装的表单验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export default {
data() {
return {
loginForm: {
username: '',
password: ''
},
rules: {
username: [{validator: this.formValid.text}],
password:[{validator: this.formValid.text}]
}
}
},
}

3.表单验证的多语言和优化

1.多语言

因为async-validator验证并不支持多语言,所以无法直接使用 message: this.$i18n.t('lang.form.userName') 来切换表单验证提示。这里我的解决方法是在formValid.js中使用变量作为提示信息,并在切换语言时添加派发事件,在formValid.js中监听事件来切换语言。
这个方法有一个问题是,无法即时修改提示语言,只能再次触发时才会修改。所以只能在切换语言时刷新页面,此时需要添加提示,使用户清楚切换语言后会清空未提交的表单。

1.在语言包中添加多语言的提示信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default lang {
nav: {
home: '首页',
lang: '多语言',
changeLang: '切换语言后会清空未提交的表单,确认切换?',
},
tip:{
prompt: '提示'
},
button:{
confirm: '确认',
cancel: '取消'
},
form: {
text: '不能为空',
}
}

2.修改切换语言方法,添加事件发送和页面刷新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
methods: {
changeLang: function (lang) {
let originalSetItem = localStorage.setItem;
window.localStorage.setItem = function (key,newValue) {
let setItemEvent = new Event('setItemEvent');
setItemEvent.newValue = newValue;
window.dispatchEvent(setItemEvent);
originalSetItem.apply(this,arguments);
};
this.$confirm(this.$i18n.t('lang.nav.changeLang'),this.$i18n.t('lang.tip.prompt'),{
confirmButtonText: this.$i18n.t('lang.button.confirm'),
cancelButtonText: this.$i18n.t('lang.button.cancel'),
type: 'warning'
}).then(()=>{
if (lang === 'zh') {
window.localStorage.setItem('lang', 'zh-CN')
this.$i18n.locale = 'zh-CN'
} else if (lang === 'en') {
window.localStorage.setItem('lang', 'en-US')
this.$i18n.locale = 'en-US'
}
this.newPage()
}).catch(()=>{

})
},
newPage: function () {
let NewPage = '_empty' + '?time=' + new Date().getTime()/1000
// 之后将页面push进去
this.$router.push(NewPage);
// 再次返回上一页即可
this.$router.go(-1);
}
}

3.修改formValid.js文件,添加多语言引入和事件监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let message;
let zhForm = require('../lang/zh').lang.form;
let enForm = require('../lang/en').lang.form
if (!window.localStorage.getItem('lang') || window.localStorage.getItem('lang') === 'zh-CN') {
message = zhForm
} else {
message = enForm
}
window.addEventListener("setItemEvent", function (e) {
if (e.newValue === 'zh-CN') {
message = zhForm
} else {
message = enForm
}
});
export default {
text: (rule, value, callback) => {
if (!value) {
return callback(new Error(message.text));
} else {
callback()
}
},
}

2.表单验证优化

element UI的官方文档中使用表单验证均为点击提交后再进行验证,这种验证使用较方便,但是刚从Angularjs转来Vue,还是很怀念Angularjs直接监听input修改来进行校验的功能,所以就想还原一下Angularjs的表单验证。

1.将提交按钮初始化为disabled,并添加一个变量来检测表单是否修改过

1
<el-button type="primary" style="width:100%" @click="" :disabled="formInvalid">{{$t('lang.user.login')}}</el-button>
1
2
3
4
5
6
7
8
export default {
data(){
return {
formInvalid: true,
formTrigger: false,
}
}
}

2.表单的输入框添加 @input 监听输入修改

注意: 和Angularjs中的ng-change方法不同,vue中@change方法仅能在输入框blur时才会执行。

1
2
3
4
5
6
7
8
9
10
<el-form-item prop="username">
<el-input v-model="loginForm.username" :placeholder="$t('lang.user.username')" class="with-icon-input" @input="formChange()">
<i class="fa fa-user" slot="prefix" style="margin-left:5px"></i>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginForm.password" :placeholder="$t('lang.user.password')" type="password" class="with-icon-input" @input="formChange()">>
<i class="fa fa-lock" slot="prefix" style="margin-left:5px"></i>
</el-input>
</el-form-item>

3.添加监听方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
methods: {
formChange: function () {
for (let key in this.loginForm) {
if (!this.formTrigger){
if (!this.loginForm[key]){
return
}
}
}
this.$refs['loginForm'].validate((valid)=>{
this.formTrigger = true;
if (valid) {
this.formInvalid = false
} else {
this.formInvalid = true
}
});
}
}

引申

在一些网站的用户注册时,会即时检测当前输入的用户名是否已经被注册过。此时就可以在输入改变时添加http请求,后台在数据库中查重。但是有时候用户输入会较快,若在每次输入改变后都发送一次请求,会因为堆积很多pending请求影响浏览器性能。
解决方法:
在方法中添加防抖动,在用户停止输入一段时间后再执行请求:

  1. npm安装
    npm i --save-dev lodash
  2. 按需引入
    import lodash from 'lodash'
  3. 方法中添加防抖:
    1
    2
    3
    formChange: lodash.debounce(function () {
    //http请求
    },300)

  • 版权声明: 本文章采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处❤
0%