1. 前言
(1) 资料
vue-router的官方文档如下:
https://router.vuejs.org
(2) 需求
本文是在上篇《使用vue-i18n实现多语言》功能的引申。需要实现的功能如下:
- 多语言需要反映在url上,英文、简体中文、繁体中文页面需分别为/en、/zhCHS、/zhCHT
- 页面切换后,也能记住上页中选择的语言
- 在页面中先切换语言再刷新,也显示之前选择的语言
- 应用的基路径不在根目录下,而是多一级/snycard2018
- 如果用户load的页面是根目录,要自动定位到正确目录下并以英文作为默认语言
(3) 工程基本情况
[1] vue-router的安装
在Vue init时有选项:[Install vue-router?]。如果选择了yes,会自动安装vue-router。如果没有安装,可以用如下命令进行安装:
npm install vue-router
完成后,工程src目录下有router的文件夹,里面的index.js用来设置路由。
[2] 结构设计
如下图,语言选择的部分,由于所有页面都用,所以在Header.vue中。通过router来切换home页与about页。
2. 实战
(1) 动态路由
在这一小节中解决的问题是:
- 如何让localhost:8080/en、localhost:8080/zhCHS、localhost:8080/zhCHT都指向Home.vue这个component;而localhost:8080/en/about(其他两种语言略)指向About.vue
- 如何使用路由进行传参,让页面加载时知道url上面带的是哪种语言
[1] 动态路径参数设置
动态路径参数,以冒号开头。如下router文件夹下的index.js中的配置。根目录下的二级名称就作为lang参数的值。
//index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/page/home/home'
import About from '@/page/about/about'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/:lang', //<----【看这里】
component: Home,
},
{
path: '/:lang/about',//<----【看这里】
component: About
}
]
})
[2]获取动态路由参数值
以下代码都在App.vue进行修改。
1) DOM中
通过{{$route.params.参数名}}
可以获得该值,如下:
//Jade(Pug)语法
div language: {{$route.params.lang}}
2) 方法中
通过this.$route.params.参数名
获得该值,并赋给vue-i18n的全局配置参数叫locale控制语言显示。
mounted(){
this.$i18n.locale = this.$route.params.lang;
}
(2) 父子组件之间的通信
在这一小节中解决的问题是:
- 如何将路由的语言参数传递到Header.vue中,并且显示出来
- 在Header.vue中选择了语言,App.vue中如何获得 。
官网组件内容:
https://cn.vuejs.org/v2/guide/components.html
[1] 父组件通过 prop向子组件传参
父组件的数据需要通过 prop 才能下发到子组件中。
项目中语言这个参数的管理统一放在了父级App.vue中,这样子组件需要这个属性的话,由父组件传递过去,以免混乱。
1) App.vue
在App.vue中定义一个data为lang,将其绑定到HeadTop这个组件上。页面在加载的时候将路由参数赋给data中的lang。
//--jade--
#app
//-Header-
HeadTop(v-bind:lang="lang") //<----【看这里】
//-router-
div.main
router-view
//--js--
import HeadTop from "./components/Header"
export default {
name: 'app',
//-data-
data(){
return{
lang: ''//<----【看这里】
}
},
//-components-
components:{
HeadTop
},
//-mounted-
mounted(){
this.$i18n.locale=this.$route.params.lang;
this.lang=this.$route.params.lang;//<----【看这里】
}
}
2) Header.vue
//--jade--
p current language: {{lang}}
//--js--
export default {
props:['lang']
}
[2] 子组件通过自定义事件跟父组件通信
使用 $emit(event, […args])
触发事件。
1) Header.vue
将点击事件绑定到changeLocale
方法上并传入语言参数。点击事件触发自定义事件changeAppLocale
,且参数为locale。
//--jade--
div
a(@click="changeLocale('en')") English //<----【看这里】
a(@click="changeLocale('zhCHS')") 简体中文
a(@click="changeLocale('zhCHT')") 繁體中文
p current language: {{lang}}
//--js--
export default {
props:['lang'],
methods:{
changeLocale(locale){
this.$emit('changeAppLocale',locale);//<----【看这里】
}
}
}
1) App.vue
将自定义事件绑定到HeadTop上。当点击触发了click事件连带触发自定义事件changeAppLocale(@changeAppLocale
),就会执行changeAppLocale方法(等号后面定义的方法名)。
//--jade--
HeadTop(@changeAppLocale="changeAppLocale" v-bind:lang="lang")//<----【看这里】
//--js--
export default {
methods:{
changeAppLocale(locale){//<----【看这里】
console.log(locale);
}
}
}
(3) 编程式导航
在这一小节中解决的问题是:
- 页面之间跳转如何带上语言
- 如何在选择语言后,反映在路由上
官网编程式的导航:
https://router.vuejs.org/zh-cn/essentials/navigation.html
除了使用 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
【注意】在 Vue 实例内部,你可以通过
$router
访问路由实例。因此你可以调用this.$router.push
。
导航有两种方式,他们等价。
1) 声明式
<router-link :to="...">
2) 编程式
router.push(...)
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
[1] 页面间的跳转
由于我们的路由中带了参数lang
,所以上述最适合的是[命名的路由]。这就需要给路由命名。
//router ->index.js
export default new Router({
mode: 'history',
routes: [
{
path: '/:lang',
name:'home',//<----【看这里】
component: Home,
},
{
path: '/:lang/about',
name:'about',//<----【看这里】
component: About
}
]
})
App.vue中将data中的lang属性绑定到路由上,以便传递到Home.vue及About.vue中。
//App.vue - jade
#app
//-Header-
HeadTop(@changeAppLocale="changeAppLocale" v-bind:lang="lang")
//-router-
div.main
router-view(v-bind:lang="lang" )//<----【看这里】
这两个页面跳转功能相同,我们使用两种方式,分别实现:
1) About.vue跳转home
采用声明式。
//--jade--
router-link(:to="{name:'home',params: {lang: this.lang}}") link to Home//<----【看这里】
//--js--
export default {
name:'about',
props: ['lang']//<----【看这里】
}
2) Home.vue跳转about
//--jade--
a(@click="goto") link to About
//--js--
export default {
name: 'home',
props: ['lang'],
methods:{
goto(){
this.$router.push({name:'about',params: {lang: this.lang}})//<----【看这里】
}
}
}
[2] 切换语言时同步路由
在上一小节中我们在App.vue定义了changeAppLocale
方法。按照需求,切换了语言,需要改变路由。而问题在于在App.vue中我并不知道当前的页面是哪一个。
可以通过this.$route.name
获得当前router的名称,在切换语言时,不会切换页面,所以name保持不变。
export default {
name: 'app',
data(){
return{
lang: ''
}
},
components:{
HeadTop
},
methods:{
changeLanguage(lang){
this.$i18n.locale=lang;
this.lang=lang;
},
changeAppLocale(locale){
this.changeLanguage(locale);
this.$router.push({name: this.$route.name, params: {lang: this.lang}})//<----【看这里】
}
},
mounted(){
this.changeLanguage(this.$route.params.lang);
}
}
(4) 设置基路径
到这一步,所有功能已经完成啦。下面进行另外一个需求的实现——应用的基路径不在根目录下,而是多一级/snycard2018。
官网Router构造配置base:
https://router.vuejs.org/zh-cn/api/options.html#base
base
类型: string
默认值: “/”
应用的基路径。例如,如果整个单页应用服务在 /app/ 下,然后 base 就应该设为 “/app/”。
所以,只需在router中设置base为'/cnycard2018/'
//router - index.js
export default new Router({
mode: 'history',
base: '/cnycard2018/',//<----【看这里】
routes: [
{
path: '/:lang',
name:'home',
component: Home,
},
{
path: '/:lang/about',
name:'about',
component: About
}
]
})
(5) 重定向
根目录下,或者错误的url地址,需要都强制到首页并默认为en模式,如下。需要注意的是由于设置了base,所有路径都会自动在base之下,所以redirect只用写到/en。
//router - index.js
export default new Router({
mode: 'history',
base: '/cnycard2018/',
routes: [
{
path: '/:lang',
name:'home',
component: Home,
},
{
path: '/:lang/about',
name:'about',
component: About
},
{
path: '*',//<----【看这里】
redirect: "/en"//<----【看这里】
},
]
})
查看完整工程:https://github.com/Joyce-Liu/vue-router-and-multi-lang