全局路由配置
全局的路由配置与原本的vue的router写法几乎没有差别,只是多了个类型检查。
// router/index.ts
import 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.ts
import 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'
@Component
export 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
也没有什么问题了,因此还是推荐使用第二种方式。