全局路由配置

全局的路由配置与原本的vue的router写法几乎没有差别,只是多了个类型检查

  1. // router/index.ts
  2. import Vue from 'vue'
  3. import VueRouter, { RouteConfig } from 'vue-router'
  4. import Home from '../views/Home.vue'
  5. Vue.use(VueRouter)
  6. // 引入RouteConfig类型为各个路由添加类型检查
  7. const routes: Array<RouteConfig> = [
  8. {
  9. path: '/',
  10. name: 'Home',
  11. component: Home,
  12. // 路由独享守卫
  13. beforeEnter: (to, from, next) => {
  14. // ...
  15. }
  16. },
  17. {
  18. path: '/about',
  19. name: 'About',
  20. // route level code-splitting
  21. // this generates a separate chunk (about.[hash].js) for this route
  22. // which is lazy-loaded when the route is visited.
  23. component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),
  24. },
  25. ]
  26. const router = new VueRouter({
  27. routes,
  28. })
  29. // 全局路由导航守卫
  30. router.beforeEach((_to, _from, next) => {
  31. console.log('beforeEach')
  32. next()
  33. })
  34. router.afterEach((to, from) => {
  35. // afterEach没有next回调
  36. console.log('afterEach', to, from)
  37. })
  38. export default router

组件内的路由导航守卫

方式一:写在@Component装饰器内

组件内的导航守卫Hook可以直接写在@Component的装饰器内。

  1. import { Component, Vue } from 'vue-property-decorator'
  2. @Component({
  3. beforeRouteLeave(to, from, next) {
  4. console.log('beforeRouteLeave', to, from)
  5. next()
  6. }
  7. })
  8. export default class App extends Vue {}

用这个方式没有学习成本,与js写法没有差异。且无需手动声明钩子函数的参数类型,官方已经声明好了。
但是该方法存在着一个较大的问题。就是在钩子内使用 this 时,无法提供完整的代码提示!

  1. import { Component, Vue } from 'vue-property-decorator'
  2. @Component({
  3. beforeRouteLeave(_to, _from, next) {
  4. // 代码能够正常运行,打印出 韩梅梅
  5. // 但是编译器无法识别,会报出 Property 'userName' does not exist on type 'Vue'. 的错误
  6. console.log(this.userName)
  7. next()
  8. }
  9. })
  10. export default class App extends Vue {
  11. public userName = '韩梅梅'
  12. }

因此为了解决 this 组件实例的访问提示,还支持第二种钩子写法。

方式二:写在class内(推荐)


入口文件 main.ts中**
在组件的class内直接使用导航守卫的Hook时,会发现钩子并不能生效。因此需要先在主入口 main.ts 中注册导航守卫相关的钩子。

  1. // main.ts
  2. import Vue from "vue";
  3. import App from "./App.vue";
  4. import router from "./router";
  5. // 为Component装饰器注入钩子
  6. import Component from 'vue-class-component'
  7. Component.registerHooks([
  8. 'beforeRouteEnter',
  9. 'beforeRouteLeave',
  10. 'beforeRouteUpdate'
  11. ])
  12. new Vue({
  13. router,
  14. render: h => h(App)
  15. }).$mount("#app");

.vue组件内
main.ts中注册好钩子后,就能直接在class中写对应的导航守卫钩子了。
要从 vue-router 模块中引入 Route, NavigationGuardNext 并手动给钩子函数的参数定义类型。
不手动添加类型时,ts默认会将这些参数认为是any类型,会有警告。

  1. // .vue组件内
  2. import { Component, Vue } from 'vue-property-decorator'
  3. import { Route, NavigationGuardNext } from 'vue-router'
  4. @Component
  5. export default class App extends Vue {
  6. private beforeRouteEnter(to: Route, from: Route, next: NavigationGuardNext) {
  7. // 在渲染该组件的对应路由被 confirm 前调用
  8. // 不!能!获取组件实例 `this`
  9. // 因为当守卫执行前,组件实例还没被创建
  10. console.log('beforeRouteEnter', to, from)
  11. next()
  12. }
  13. private beforeRouteUpdate(_to: Route, _from: Route, next: NavigationGuardNext) {
  14. // 在当前路由改变,但是该组件被复用时调用
  15. // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
  16. // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
  17. // 可以访问组件实例 `this`
  18. console.log('beforeRouteEnter', this)
  19. next()
  20. }
  21. private beforeRouteLeave(_to: Route, _from: Route, next: NavigationGuardNext) {
  22. // 导航离开该组件的对应路由时调用
  23. // 可以访问组件实例 `this`
  24. console.log('beforeRouteLeave', this)
  25. next()
  26. }
  27. }

虽然第二种方式稍微麻烦一点,但是使用第二种方式代码提示就很完善了,访问 this 也没有什么问题了,因此还是推荐使用第二种方式。