学习目标:
根据vue-router官网和我工作中实际运用到的地方简洁的总结vue-router中的进阶知识点,基础版以在上一篇文章发布。
导航守卫
导航守卫,说白了就是在路由跳转的时候,vue暴露的一些钩子方法,让我们可以在路由跳转的时候进行控制。
记住参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。
全局前置守卫(router.beforeEach)
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
当导航发生变化的时候,未发生路由跳转的时候调用
- to: Route: 即将要进入的目标 路由对象
- from: Route: 当前导航正要离开的路由
- next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
执行next()继续跳转,next({path:xxx})跳转到哪,next(false)终止跳转,如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
这个方法可以用来做前端的权限校验,比如说不同角色的用户,进入到同一个路由之后的系统的行为是不同的,这时候我们就可以在这加逻辑,跳转我们对应的路由,或者做一些处理。
确保 next 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错
全局解析守卫
在 2.5.0+ 你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
全局后置钩子
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:因为它是后置的吗,路由跳转完了,还跳转干啥。
router.afterEach((to, from) => {
// ...
})
路由独享守卫
你可以在路由配置上直接定义 beforeEnter 守卫:这个钩子只在当前路由有效
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`
}
}
beforeRouteEnter 守卫不能访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。
不过,你可以通过传一个回调给 next来访问组件实例
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
})
}
注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。
完整的导航解析流程
- 导航被触发
- 在失活的组件里调用 beforeRouteLeave 守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
小总结
这时候有很多小伙伴会发现了,有一些钩子函数的功能已经涵盖了别的钩子函数,那我就记得这一个钩子函数就行了,以后写逻辑都在这里面写,都一样的,千万不要这么做,方法细分为了就是让你在编写代码的时候能够能够细分功能领域,如果你把逻辑都写在一起,你永远不知道有多么的恶心,维护起来有多么的费劲。
滚动行为
在路由切换的时候,默认滚动是会保持不变的,所以vue给我们提供了一个方法,来让我们在路由切换的时候控制滚动行为,来达到我们预期的效果。
当创建一个 Router 实例,你可以提供一个 scrollBehavior 方法:
const router = new VueRouter({
routes: [...],
scrollBehavior (to, from, savedPosition) {
// return 期望滚动到哪个的位置
}
})
对于所有路由导航,简单地让页面滚动到顶部。
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
返回 savedPosition,在按下 后退/前进 按钮时,就会像浏览器的原生表现那样:
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0 }
}
}
如果你要模拟“滚动到锚点”的行为:
scrollBehavior (to, from, savedPosition) {
if (to.hash) {
return {
selector: to.hash
}
}
}
路由懒加载
在 Webpack 2 中,我们可以使用动态 import语法来定义代码分块点 (split point):也就是说webpack会根据Import()语法来分包,做到路由懒加载,做到首屏加载的包的体积变小的目的,需要的时候在加载,但是我个人认为吧,这个毕竟是懒加载自己写的代码,效果有不是太多,毕竟自己写的代码体积很小吗,跟一些第三方包没法比。
这就是如何定义一个能够被 Webpack 自动代码分割的异步组件。
const vouCase = () => import('../views/vouCase/vouCase.vue')
把组件按组分块
有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
总结
vue-router完。vue-router-api