vue-router使用复习

在vue脚手架中使用vue-router时,需要在main文件中使用下面的配置

1
2
3
4
5
6
7
8
import Vue from 'vue'
import App from './App.vue'
import router from './router.js'

new Vue({
router,
render: h => h(App)
}).$mount('#app')

这段代码做了两件关键的事情

  1. 引入router,在引入时执行了router.js里的文件内容
  2. 在创建vue实例时传入了router的配置

然后我们看看router.js里的文件配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import Vue from 'vue';
import Router from './vue-router';
import Home from './views/Home';
import About from './views/About';

Vue.use(Router);

let router = new Router({
mode: 'hash',
routes: [{
path: '/',
component: Home
},
{
path: '/about',
component: About,
children: [{
path: 'a',
component: {
render:(h)=><h1>About Child A</h1>
}
},
{
path: 'b',
component: {
render:(h)=><h1>About Child B</h1>
}
}]
}
]
})

export default router

这个文件关键的代码也有两处

  1. 调用了Vue.use,安装Router插件
  2. 调用了new Router创建一个Router配置对象并导出

在了解了这些后,我们正式开始实现一个vue-router

实现Router

从上面的使用方法我们可以看出,Router是一个类,而且提供了Router.install方法(Vue.use会调用这个方法)

用代码表现大致如下

1
2
3
4
5
6
7
8
9
10
import install from './install'

class VueRouter {
constructor(options : RouterOptions) {

}
}
VueRouter.install = install

export default VueRouter;

我们来看看install方法,install方法要进行一些数据的混合,还有一些初始化操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import {VueConstructor} from "vue";

export let _Vue : VueConstructor;
import Link from './components/link';
import View from './components/view';

export default function install(Vue : VueConstructor | any, options : any){
// 插件安装的入口
_Vue = Vue; // 保存Vue.use时传入的Vue对象,以供其他文件使用
// 给所有组件都混入一个属性 router
Vue.mixin({
beforeCreate(this : Vue | any) {
// 只有根实例才传入了router的配置
// 如果是根实例,保存_routerRoot和_router到实例上
if(this.$options.router){
this._routerRoot = this;
this._router = this.$options.router;
// 调用Router的init方法对路由进行初始化
this._router.init(this);
}else{
// 如果不是根实例,使用父组件的_routerRoot
this._routerRoot = this.$parent && this.$parent._routerRoot;
}
}
});

// 注册全局组件
Vue.component('router-link',Link);
Vue.component('router-view',View);
}

然后控制权又回到了Router类里,Router需要根据当前的路径匹配对应的组件,还有根据不同的模式对路由进行处理,所以我们创建一个匹配器用于匹配路径,创建一个History对象对路由进行处理,因为hash模式和history模式,本质上都是监听事件进行跳转,所以我们可以抽出一个公共的父类处理共同的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import HashHistory from './history/hash';
import BrowserHistory from './history/history';
import {History} from './history/base';
import createMatcher from './create-matcher';

class VueRouter {

matcher !: {
addRoutes : Function,
match : Function
};
history !: History;
static install : Function;

constructor(options : RouterOptions) {
// 根据用户的配置 和当前请求的路径 渲染对应的组件
// 创建匹配器 用于后续的匹配操作
this.matcher = createMatcher(options.routes || []);

// 需要根据不同的 路径进行切换
options.mode = options.mode || 'hash'; // 默认没有传入就是hash模式
switch (options.mode) {
case 'hash':
this.history = new HashHistory(this);
break;
case 'history':
this.history = new BrowserHistory(this);
break;
}
this.beforeHooks = [];
}
}

看看匹配器的代码,比较简单,就是创建一个路由映射map,然后返回一个匹配的方法而已