# vue-router 使用复习

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

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 里的文件配置

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 会调用这个方法)

用代码表现大致如下

import install from './install'
class VueRouter {
    constructor(options : RouterOptions) {
    }
}
VueRouter.install = install
export default VueRouter;

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

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 模式,本质上都是监听事件进行跳转,所以我们可以抽出一个公共的父类处理共同的逻辑

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,然后返回一个匹配的方法而已

更新于 阅读次数