前言
vue基于类的写法,和基于对象的写法并不一致。
使用vue-cli3创建的项目,src
目录下的文件结构并没有多大区别,store
、router
、app
、view
、components
、aeests
该有的还是有的。
但是,多了一个东西:vue-property-decorator
,vue-property-decorator
是vue-class-component
的超集。
import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator';
最主要的区别就是这里,组件的定义,参数的接受,方法的定义,等等。
但是本文主要讲的是router的监听。
路由监听
用vue2的vue-cli创建项目,在src
下有App.vue
,main.js
,其中如果要做路由权限控制,可以通过在mian.js
添加以下代码来控制:
import router from './router'
router.beforeEach((to, from, next) => {
/*如果需要登录,当前没有登录,直接跳转到登录页*/
if (to.meta.Auth && !store.state.loginStatus) {
return next({ name: 'Login', query: {path: to.name}})
}
next()
})
这个功能,在新版本的vue3中依然可以使用,因为使用了typescript
,所以应该是main.ts
文件。
但是如果要在组件内部使用路由监听,就遇到问题了,路由钩子beforeRouteEnter
,beforeRouteLeave
,beforeRouteUpdate
不生效。
官网推荐在mian.ts
中注册解决:
import Component from 'vue-class-component'
Component.registerHooks([
'beforeRouteEnter',//进入路由之前
'beforeRouteLeave',//离开路由之前
'beforeRouteUpdate'
])
但是在vue-cli3中试过,不生效。可能是vue-property-decorator
和vue-class-component
有区别的原因,或者项目配置问题。
组件中实现路由监听,只能通过@Watch('$route')
来实现。
但是@Watch
不是路由守卫,如果离开当前组件,就不能继续监听路由变化,所以需要在当前的router-virew
容器组件中监听。
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator';
@Component
export default class App extends Vue {
@Watch('$route',{ immediate: true })
private changeRouter(route: Route){
console.log(route)
}
}
</script>
其中{ immediate: true }
是关键,必须加这个参数才嫩实现对$route
的监听。
结语
vue-cli3+typescript的规范还不成熟,各种文档还不够齐全,尤其是中文文档。
很多demo都是基于vue2改造的,导致使用vue-cli3的时候出bug。
尤其是vue-router
和vuex
的使用。
但也正是这些问题,让我们有更大的兴趣学习使用这个新的技术规范。
后记
经过社区同学的指点,使用路由钩子的组件必须由路由加载,做了测试,vue-cli3的路由守卫是可以使用的。
入口文件:
//main.ts
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import { Component } from 'vue-property-decorator';
Vue.config.productionTip = false;
Component.registerHooks([
'beforeRouteEnter',
'beforeRouteLeave',
'beforeRouteUpdate',
]);
new Vue({
router,
store,
render: (h) => h(App),
}).$mount('#app');
路由规则文件:
//router.ts
import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';
Vue.use(Router);
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home,
},
{
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'),
},
],
});
路由载入组件:
//About.vue
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class About extends Vue {
beforeRouteEnter(to: Route, from: Route, next: () => void): void {
console.log('beforeRouteEnter');
next();
}
beforeRouteUpdate(to: Route, from: Route, next: () => void): void {
console.log('beforeRouteUpdate');//暂时不生效,版本问题
next();
}
beforeRouteLeave(to: Route, from: Route, next: () => void): void {
console.log('beforeRouteLeave');
next();
}
}
</script>
如上,可以愉快的使用单独的路由钩子啦!!!