使用Vue Router 也有两三年了。都是零零散散自己写在印象笔记里面,一直没有系统总结过路由的知识点,都是需要用到再去看下文档或者文章。这次把我自己经常用到的路由知识点写下来,以后好自己翻看。
1.嵌套路由
1.1 渲染出口
我们平常写的 Vue 项目页面都是由多个组件嵌套成的,所以相应的,路由也需要有嵌套层级。
<router-view> 是渲染组件的出口,我们一般在 id = 'app'里面设置顶层的渲染出口。
<div id="app">
<router-view></router-view>
</div>
1.2 嵌套路由
routers 是一个数组对象,可以包含多个路由,也就是多个对象。每一个路由对象里面可以设置children 属性,然后children值又是一个数据对象。依次类推,可以一直嵌套下去。
const router = new VueRouter({
routes: [
{
path: '/user',
component: User,
children: [
{
path: '/info',
component: Info,
children: [
{
path: '/name',
component: Name,
// 还可以嵌套 children 数组。
}
]
}
]
}
]
})
1.3 根路径
要注意,以 / 开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。
以上是Vue Router官网的关于根路由的一个解释。具体的意思:
- 单纯的 / 会被当做网站的根路径,也就是初始访问路由。
- 设想如果没有这条规则的话,那我们就需要在 / 路径下面再设置一个 children 属性。具体可以看下面的代码和1.2 的代码对比。
const router = new VueRouter({
routes: [
{
path: '/',
children: [
{
path: '/user',
component: User,
children: [
{
path: '/info',
component: Info,
// 还可以嵌套 children 数组。
}
]
}
]
}
]
})
2.动态路由
2.1 动态匹配路由
如果我们想要使用动态路由,比如用户详情页。不管是/user_detail/4,还是/user_detail/5。我们都想要匹配到同一个组件。这时候就可以使用动态路由了。
具体方法:
{
path: '/user_detail/:id',
component : Detail
}
但是要注意的是,如果从是/user_detail/4跳转到/user_detail/5,组件会被复用。也就是说,组件的生命周期不会再次创建。
2.2 匹配 404 页面
如果想要匹配所有的路径,可以使用 * 来匹配。因为是匹配所有的路径,所以要放在最后。
具体用法:
{
path: '*',
component : Error,
}
然后写一个 Error.vue 的页面既可。
3.同级多视图
有时候我们想要在一个路由里面,写上多个视图。比如在根路径 / 里面。 我们想要分出三个视图,分别是:顶部视图(个人信息,退出,网页 logo 等),侧边栏视图,主体视图(展示网站主要内容)。这时候同级多视图就派上用场了。
本来我们只需要写一个<router-view></router-view>,作为渲染出口即可。现在我们想要多个视图,只需要多添加几个<router-view></router-view>,并给多出来的视图加上命名。
<router-view></router-view>
<router-view name="a"></router-view>
<router-view name="b"></router-view>
注意,在配置里面的 component属性要加上 s 变成components。
然后 default 是匹配没有命名的<router-view></router-view>。
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: C,
a: A,
b: B
}
}
]
})
4.重定向和别名
重定向:当用户访问路由 a 的时候,我们把它定向到 b。
最常见的就是当用户访问根路径的时候,我们把它重定向到首页或是登录页面。
使用 redirect 这个属性来重定向。
1.直接使用path 重定向
{ path: '/a', redirect: '/b' }
2.使用 name 来重定向
{ path: '/a', redirect: { name: 'b' }}
3.使用方法来进行重定向。
{path: '/a', redirect: to => {
// 随机重定向。
if (Math.random() > 0.5) {
return { path: '/c'}
}else {
return '/b'
}
},
}}
别名
顾名思义,给路由起另一个名字。比如一个人朋友叫他张三丰,下属叫他张总,老板叫他小张,其实都是指向同一个人。
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。
const router = new VueRouter({
routes: [
{ path: '/a', component: A, alias: '/b' }
]
5.路由导航
我们要是在页面上直接导航的话,使用<router-link to="/bar">Go to Bar</router-link> 标签即可,浏览器会把router-link标签渲染成一个 a 标签。
但是我们要是想要在JS 里面通过点击,或者通过特定的条件再跳转。这就需要使用到编程式导航了,编程式导航一共有三种。
4.1 router.push
这个方法会向浏览器的 history 推入一个新的地址,点击浏览器的后退按钮也可以返回上一步的地址。
这个方法接受的可以是字符串,也可以是对象。
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
4.2 router.replace
这个跟router.push很像,不同之处在于,router.push是添加一个新的地址,router.replace是替换当前的地址。
这个方法的接受参数跟router.push一样。既可以是字符串也可以是对象。
4.3 router.go
这个方法是在浏览器记录前进或者后退几步,接收的参数是一个整数。
不过要是不成功的话,会默默失败,没有提示。比如你要是后退一百步,实际上才你打开这个标签才点击10个链接,也就是在浏览器的 history 栈才有10 个记录,这种情况下最多后退 10步。
this.$router.go(-6);
this.$router.go(2);
this.$router.go(-4);
6.路由传参
6.1 路由路径传参
通过在路由里面所要传递的传参,然后在到达的页面,使用$route.params,接受传递过来的参数。
路由写法:{ path: '/user/:id', component: User }
接收写法: this.$route.params.id
上面这种方法耦合性很高,所以可以使用 props 解耦。
路由写法:{ path: '/user/:id', props: true, component: User }
接收写法:
props:['id'],
mounted(){
console.log(this.id)
},
这样就会挂载当前组件的 data 对象上面。
6.2 params
这个 params 是和 name 配合使用的。跳转过去之后路径不会带上参数。
编程式路由写法:router.push({ name: 'user', params: { userId: '123' }})
接收写法:this.$route.params.id
6.3 query
这个 query 是和 path 配合使用的,跳转过去之后路径会带上参数变成 /search?id=1 般使用在查询方面。
编程式路由写法:router.push({ path: 'search', query: { id: '1' }})
接收写法::this.$route.query.id
7.路由守卫
当路由进行需要进行导航的时候,我们可以通过路由守卫的方式,来进行路由的跳转和和取消跳转。
路由守卫有三种,一种是全局的守卫,一种是路由的守卫,一种是组件的守卫。
7.1 全局守卫
全局守卫一般用来验证是否已经登陆。如果登陆,就进行,没有登录就跳转到登录页面。
router.beforeEach((to, from, next) => {
/* 必须调用 `next`
常用这个
*/
})
router.beforeResolve((to, from, next) => {
/* 必须调用 `next` */
})
router.afterEach((to, from) => {
/* 这是全局后置钩子,不会接受 next 函数,也不改变导航
*/
})
7.2 路由独享守卫
跟全局路由一样,只不过是针对单个路由,来进行设置。
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
7.3 组件守卫
组件的守卫,一共有三个;
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
8.路由懒加载
之所以要用路由懒加载,是因为如果把所有的路由都打包,会导致首屏加载时间过长,导致白屏。
Vue路由懒加载有两种方式:
第一
Vue 官方,使用 import 方式。
阮一峰ES6 文档里面介绍 import :
import()函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,就会加载指定的模块。
const Foo = () => import('./Foo.vue')
然后正常使用组件即可。
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
第二
使用 Vue 异步组件。
直接在组件里面写,一行代码可以搞定。
component:resolve=>(require(["@/components/Foo"],resolve))
注意
1.网上还有一种方法是webpack 的require.ensure()方式,实现懒加载。 2.使用懒加载后,需要修改build 的设置。在build下面的webpack.prod.conf.js 找到 publicPath:"./"