官方文档:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
一、导航守卫(类似中间件)
全局前置守卫(还有很多钩子函数,具体可看文档)
你可以使用 router.beforeEach
注册一个全局前置守卫:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// to: Route: 即将要进入的目标 路由对象
// from: Route: 当前导航正要离开的路由
// next: Function: 一定要调用该方法来 resolve 这个钩子
})
守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中
在用户未能验证身份时重定向到 /login
的示例:
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
完整的导航解析流程
- 导航被触发
- 在失活的组件里调用
beforeRouteLeave
守卫 - 调用全局的
beforeEach
守卫 - 在重用的组件里调用
beforeRouteUpdate
守卫 (2.2+)。 - 在路由配置里调用
beforeEnter
- 解析异步路由组件
- 在被激活的组件里调用
beforeRouteEnter
- 调用全局的
beforeResolve
守卫 (2.5+) - 导航被确认
- 调用全局的
afterEach
钩子 - 触发 DOM 更新
- 调用
beforeRouteEnter
守卫中传给next
的回调函数,创建好的组件实例会作为回调函数的参数传入
二、路由元信息(meta)
meta
可以携带权限信息到下一个路由
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
// a meta field
meta: { requiresAuth: true }
}
]
})
一个路由匹配到的所有路由记录会暴露为 $route
对象 (还有在导航守卫中的路由对象) 的 $route.matched
数组。因此,我们需要遍历 $route.matched
来检查路由记录中的 meta
字段
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// 此路由需要身份验证,请检查是否已登录
// 如果没有,重定向到登录页。
if (!auth.loggedIn()) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // 确保一定要调用 next()
}
})
三、过渡动效
<router-view>
是基本的动态组件,所以我们可以用 <transition>
组件给它添加一些过渡效果:
<transition>
<router-view></router-view>
</transition>
四、数据获取
进入某个路由后,需要从服务器获取数据
- 导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。可以在组件的
created
钩子中获取数据 - 导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。可以在组件的
beforeRouteEnter
守卫中获取数据,当数据获取成功后只调用next
方法。
具体例子可看文档:数据获取部分
五、滚动行为(scrollBehavior )
注意: 这个功能只在支持
history.pushState
的浏览器中可用
const router = new VueRouter({
routes: [...],
scrollBehavior (to, from, savedPosition) {
// return 期望滚动到哪个的位置
return { x: 0, y: 0 }
}
})
六、路由懒加载
路由已经设置好了,此时可以按需加载
const Foo = () => import('./Foo.vue')
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
把组件按组分块
有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中
// 把这些包都放在group-foo上
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')