全局路由配置
全局的路由配置与原本的vue的router写法几乎没有差别,只是多了个类型检查。
// router/index.tsimport Vue from 'vue'import VueRouter, { RouteConfig } from 'vue-router'import Home from '../views/Home.vue'Vue.use(VueRouter)// 引入RouteConfig类型为各个路由添加类型检查const routes: Array<RouteConfig> = [{path: '/',name: 'Home',component: Home,// 路由独享守卫beforeEnter: (to, from, next) => {// ...}},{path: '/about',name: 'About',// route level code-splitting// this generates a separate chunk (about.[hash].js) for this route// which is lazy-loaded when the route is visited.component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'),},]const router = new VueRouter({routes,})// 全局路由导航守卫router.beforeEach((_to, _from, next) => {console.log('beforeEach')next()})router.afterEach((to, from) => {// afterEach没有next回调console.log('afterEach', to, from)})export default router
组件内的路由导航守卫
方式一:写在@Component装饰器内
组件内的导航守卫Hook可以直接写在@Component的装饰器内。
import { Component, Vue } from 'vue-property-decorator'@Component({beforeRouteLeave(to, from, next) {console.log('beforeRouteLeave', to, from)next()}})export default class App extends Vue {}
用这个方式没有学习成本,与js写法没有差异。且无需手动声明钩子函数的参数类型,官方已经声明好了。
但是该方法存在着一个较大的问题。就是在钩子内使用 this 时,无法提供完整的代码提示!
import { Component, Vue } from 'vue-property-decorator'@Component({beforeRouteLeave(_to, _from, next) {// 代码能够正常运行,打印出 韩梅梅// 但是编译器无法识别,会报出 Property 'userName' does not exist on type 'Vue'. 的错误console.log(this.userName)next()}})export default class App extends Vue {public userName = '韩梅梅'}
因此为了解决 this 组件实例的访问提示,还支持第二种钩子写法。
方式二:写在class内(推荐)
入口文件 main.ts中**
在组件的class内直接使用导航守卫的Hook时,会发现钩子并不能生效。因此需要先在主入口 main.ts 中注册导航守卫相关的钩子。
// main.tsimport Vue from "vue";import App from "./App.vue";import router from "./router";// 为Component装饰器注入钩子import Component from 'vue-class-component'Component.registerHooks(['beforeRouteEnter','beforeRouteLeave','beforeRouteUpdate'])new Vue({router,render: h => h(App)}).$mount("#app");
.vue组件内
main.ts中注册好钩子后,就能直接在class中写对应的导航守卫钩子了。
要从 vue-router 模块中引入 Route, NavigationGuardNext 并手动给钩子函数的参数定义类型。
不手动添加类型时,ts默认会将这些参数认为是any类型,会有警告。
// .vue组件内import { Component, Vue } from 'vue-property-decorator'import { Route, NavigationGuardNext } from 'vue-router'@Componentexport default class App extends Vue {private beforeRouteEnter(to: Route, from: Route, next: NavigationGuardNext) {// 在渲染该组件的对应路由被 confirm 前调用// 不!能!获取组件实例 `this`// 因为当守卫执行前,组件实例还没被创建console.log('beforeRouteEnter', to, from)next()}private beforeRouteUpdate(_to: Route, _from: Route, next: NavigationGuardNext) {// 在当前路由改变,但是该组件被复用时调用// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。// 可以访问组件实例 `this`console.log('beforeRouteEnter', this)next()}private beforeRouteLeave(_to: Route, _from: Route, next: NavigationGuardNext) {// 导航离开该组件的对应路由时调用// 可以访问组件实例 `this`console.log('beforeRouteLeave', this)next()}}
虽然第二种方式稍微麻烦一点,但是使用第二种方式代码提示就很完善了,访问 this 也没有什么问题了,因此还是推荐使用第二种方式。
