Vue-Router简介
Vue-Router是Vue.js官方维护的路由插件,同时也是官方推荐的路由插件。它与Vue.js内核深度结合,让开发单页应用更加容易简便。
基本配置
- **HTML **
当
对应的路由匹配成功,将自动设置 class 属性值 .router-link-active
Hello App!
Go to Foo
Go to Bar
- JavaScript
Vue.use(VueRouter)
//定义路由
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
//创建router实例
const router = new VueRouter({
routes // (缩写)相当于 routes: routes
})
//挂载实例
const app = new Vue({
router
}).$mount('#app')
动态路由配置
-
场景:通过URL传递参数
const router = new VueRouter({ routes: [ // 动态路径参数 以冒号开头 { path: '/user/:id', component: User } ] })
动态路径参数使用冒号
:
标记,对应的值都会设置到$route.params
中。此处可通过this.$route.params.id
来获取id,在模板中可以省略this.
,如const User = { template: '
User {{ $route.params.id }}' } 如果是非必须的参数,可在参数后加一个
?
,如path:''/page1/:id?'
对于带查询参数的URL,如/page1?id=123
可用$route.query
访问,如果没有查询参数,则是个空对象。
响应路由参数的变化
当使用路由参数时,例如从 /page1/123
导航到 /page1/321
,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
复用组件时,想对路由参数的变化作出响应的话,你可以简单地watch
(监测变化) $route
对象。
watch: {
'$route' (to, from) {
// 对路由变化作出响应...
}
}
或者使用 2.2 中引入的 beforeRouteUpdate
守卫:
beforeRouteUpdate (to, from, next) {
// react to route changes...
// don't forget to call next()
}
嵌套路由
实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件。借助 vue-router
,使用嵌套路由配置,就可以很简单地表达这种关系。
使用 children
配置
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User,
children: [
{
// 当 /user/:id/profile 匹配成功,
// UserProfile 会被渲染在 User 的 中
path: 'profile',
component: UserProfile
},
{
// 当 /user/:id/posts 匹配成功
// UserPosts 会被渲染在 User 的 中
path: 'posts',
component: UserPosts
}
]
}
]
})
编程式导航
除了使用
创建a
标签来定义导航链接,我们还可以借助router
的实例方法,通过编写代码来实现。
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由-> /user/123
router.push({ name: 'user', params: { userId: 123 }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path,params 会被忽略
const userId = 123
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
命名路由
有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。命名路由可以通过$route.name
来获取名称。
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
路由元信息
定义路由的时候可以配置meta
字段。可通过$route.meta
访问。
{
path: '/user/:userId',
name: 'user',
component: User,
meta: {
title: 'user'
}
}
全局钩子和路由独享的钩子
正如其名,vue-router
提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。
记住参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route
对象来应对这些变化,或使用 beforeRouteUpdate
的组件内守卫。
-
全局守卫
你可以使用
router.beforeEach
注册一个全局前置守卫:const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... })
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。
每个守卫方法接收三个参数:
- to: Route: 即将要进入的目标 路由对象
- from: Route: 当前导航正要离开的路由
- next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖
next
方法的调用参数。- next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
- next(false): 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到
from
路由对应的地址。 - next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
- next(error): (2.4.0+) 如果传入
next
的参数是一个Error
实例,则导航会被终止且该错误会被传递给router.onError()
注册过的回调。
确保要调用 next 方法,否则钩子就不会被 resolved。
-
全局解析守卫
在 2.5.0+ 你可以用
router.beforeResolve
注册一个全局守卫。这和router.beforeEach
类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。 -
全局后置钩子
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受
next
函数也不会改变导航本身:router.afterEach((to, from) => { // ... })
-
路由独享的守卫
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] })
-
组件内的守卫
最后,你可以在路由组件内直接定义以下路由导航守卫:
beforeRouteEnter
-
beforeRouteUpdate
(2.2 新增) beforeRouteLeave
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } }