写点什么

【VueRouter 源码学习】第三篇 - 路由插件 install 的实现

用户头像
Brave
关注
发布于: 4 小时前
【VueRouter 源码学习】第三篇 - 路由插件 install 的实现

一,前言


上篇,介绍了路由的配置和使用,主要包含以下内容:


  • 路由插件的安装、配置和使用;

  • 介绍了 VueRouter 主要功能,标签和属性;

  • 介绍了嵌套路由的使用和注意事项;


本篇,介绍路由插件 install 的实现;


二,路由插件 install 的实现


上一篇,介绍 VueRouter 插件的使用中提到:


执行Vue.use(Router)之后,会默认调用 Router 插件的 install 方法:

  • 在 Vue 全局注册两个组件:<router-link><router-view>

  • 为 vue 实例提供两个原型上的属性:$router$route


本篇,就来自己创建一个 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>         &nbsp        <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 实例;


下篇,创建路由映射表;

用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【VueRouter 源码学习】第三篇 - 路由插件 install 的实现