# 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') |
这段代码做了两件关键的事情
- 引入 router,在引入时执行了 router.js 里的文件内容
- 在创建 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 |
这个文件关键的代码也有两处
- 调用了 Vue.use,安装 Router 插件
- 调用了 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,然后返回一个匹配的方法而已