一,前言
上篇,介绍了路由的配置和使用,主要包含以下内容:
本篇,介绍路由插件 install 的实现;
二,路由插件 install 的实现
上一篇,介绍 VueRouter 插件的使用中提到:
执行Vue.use(Router)
之后,会默认调用 Router 插件的 install 方法:
本篇,就来自己创建一个 vue-router 插件并实现 install 插件安装逻辑;
1,创建 vue-router 目录结构
为了测试手写的 vue-router 插件,在项目中创建一个 vue-router 插件目录,并在项目中使用;
复制代码
在 vue-router 的目录中,应该包含以下几个部分:
components 目录:
包含 router-link 和 router-view 两个组件;
history 目录:
页面历史管理,包含 Hash 和 History 两种路由模式;
index.js 插件入口文件:
当引入 vue-router 时,将默认执行插件入口文件 index.js 中的逻辑;
install.js 插件安装文件:
当执行 Vue.use 加载路由插件时,将执行插件安装文件 install.js 中的逻辑;
vue-router 源码的目录结构,如下图所示:
(提取公用部分 到 base.js)
2,插件引入入口 index.js 逻辑实现
上一篇,介绍了路由的使用方式如下:
// router.js
import Vue from 'vue';
import Router from './vue-router';
Vue.use(Router);
export default new Router({
// 路由配置...
});
复制代码
从 vue-router 插件的使用方式可以看出:
vue-router 插件最终的导出结果是一个类 Router;
Router 实例化时,可以传入一个路由配置对象;
Router 类能够被 Vue.use(),说明 Router 类上包含了 install 方法;
当 vue-router 插件被引入时,会默认执行 vue-router 目录下的 index.js 入口文件;
所以,在 index.js 中创建一个 VueRouter 类,具有 install 方法,并将其导出:
// vue-router/index.js
// 导如路由安装逻辑
import install from './install'
class VueRouter {
constructor(options) { // 传入路由配置对象
}
}
// 当 Vue.use 时,会自动执行插件上的 install 方法;
VueRouter.install = install;
// 插件最终导出 VueRouter 类,外部实例化时可传入配置对象
export default VueRouter;
复制代码
3,插件安装入口 install.js 逻辑实现
install.js 最终会导出一个符合 Vue 插件机制的函数:
// vue-router/install.js
// 用于存储插件安装时传入的 Vue 并向外抛出,提供给插件中的其他文件使用
// export 的特点:如果导出的值发生变化,外部会取得变化后的新值;
export let _Vue;
/**
* 插件安装入口 install 逻辑
* @param {*} Vue Vue 的构造函数
* @param {*} options 插件的选项
*/
export default function install(Vue,options){
_Vue = Vue; // 存储插件安装时使用的 Vue
// 在 Vue 全局上注册两个组件:`<router-link>` 和 `<router-view>`;
Vue.component('router-link', {
render: h => h('a', {}, '')
});
Vue.component('router-view', {
render: h => h('div', {}, '')
});
// 在 Vue 原型上添加两个属性:`$router` 和 `$route`;
Vue.prototype.$route = {};
Vue.prototype.$router = {};
}
复制代码
在 install.js 中,主要包含以下逻辑:
插件安装时,指定插件依赖的 Vue 版本,并导出提供 vue-router 插件其他逻辑使用;
在 Vue 全局上注册两个组件:<router-link>
和 <router-view>
;
在 Vue 原型上添加两个属性:$router
和 $route
;
4,为所有组件混入 router 实例
当 new Vue 进行初始化时,会将到配置完成的 router 实例注册到 Vue 实例中,相当于在根组件中注册了 router 路由实例:
// main.js
import Vue from 'vue';
import router from './router'; // 导入配置完成的路由实例
import App from './App.vue';
const vm = new Vue({
el:'#app',
router, // 将路由实例注册到 Vue 实例中
render:(h)=>{
return h(App);
}
});
复制代码
为了使每个组件的实例都能够拿到根组件中的 router 路由实例,即:将路由实例对所有组件共享;
实现方案: 通过 Vue.mixin 为每个组件混入根组件上的 router 实例:
在每个组件创建前,为其混入 beforeCreate 生命周期函数,并绑定 router 实例,实现 router 实例在所有组件上的共享:
// vue-router/install.js
export let _Vue;
/**
* 插件安装入口 install 逻辑
* @param {*} Vue Vue 的构造函数
* @param {*} options 插件的选项
*/
export default function install(Vue, options) {
_Vue = Vue;
// 通过生命周期,为所有组件混入 router 属性
Vue.mixin({
beforeCreate() { // this 指向当前组件实例
// 将 new Vue 时传入的 router 实例共享给所有子组件
if (this.$options.router) {// 根组件才有 router
this._routerRoot = this; // 为根组件添加 _routerRoot 属性指向根组件自己
this._router = this.$options.router;// this._router 指向 this.$options.router
} else { // 子组件
// 如果是子组件,就去找父亲上的_routerRoot属性,并继续传递给儿子
this._routerRoot = this.$parent && this.$parent._routerRoot;
}
// 这样,所有组件都能够通过 this._routerRoot._router 获取到同一个 router 实例;
}
});
// 注册全局组件:router-link、router-view
Vue.component('router-link', {
render: h => h('a', {}, '')
});
Vue.component('router-view', {
render: h => h('div', {}, '')
});
// 注册原型方法 $route、$router
Vue.prototype.$route = {};
Vue.prototype.$router = {};
}
复制代码
这样,所有组件都能够通过this._routerRoot._router
获取到同一个 router 实例;
解析:
this._routerRoot = this;
this._router = this.$options.router;
可以通过 this._routerRoot._router 拿到 this.$options.router;
为子组件添加 router 实例时,通过 this.$parent._routerRoot 就可以获取到父组件上的 router 实例了;
这样,在每一个组件渲染前,通过 mixin 混入 beforeCreate 生命周期中,将最初根组件传入的 router 实例,一层一层地共享并传递下去;
复制代码
测试取 App.vue 中的 router 实例:
<template>
<div>
<!-- 添加路由切换 -->
<router-link to="/">跳转至首页</router-link>
 
<router-link to="/mine">跳转至我的</router-link>
<!-- 页面渲染结果 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name:'app',
mounted(){
console.log(this._routerRoot._router)
}
}
</script>
复制代码
在组件挂在完成后的 mounted 生命周期中输出:
三,结尾
本篇,介绍路由插件 install 的实现,主要包含以下内容:
创建 vue-router 目录结构;
插件引入入口 index.js 逻辑实现;
插件安装入口 install.js 逻辑实现;
为所有组件混入 router 实例;
下篇,创建路由映射表;
评论