详解vue-router 初始化时做了什么


Posted in Javascript onJune 11, 2018

最近因为业务需要,实现了一个简单的前端 router,正好也来看一下 vue router 是怎么实现的。这次先来一起看看 vue-router 初始化时做了什么。

vue router 的初始化使用步骤

我们首先来看 vue-router 的使用步骤,然后再分别去看各个步骤都发生了什么。

使用 vue-router 需要经过一下几个步骤:

引入 vue-router:

import VueRouter from 'vue-router';

利用 vue 的插件机制,加载 vue-router:

Vue.use(VueRouter);

实例化 VueRouter:

const router = new VueRouter({
routes
})

实例化 Vue:

const app = new Vue({
router
}).$mount('#app');

Vue 的插件机制

vue 提供了一个 use 方法,来加载插件:

Vue.use = function (plugin: Function | Object) {
 const installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
 if (installedPlugins.indexOf(plugin) > -1) {
  return this;
 }

 // additional parameters
 const args = toArray(arguments, 1);
 args.unshift(this);
 if (typeof plugin.install === 'function') {
  plugin.install.apply(plugin, args);
 } else if (typeof plugin === 'function') {
  plugin.apply(null, args);
 }
 installedPlugins.push(plugin);
 return this;
}

该方法首先检查插件是否已经加载,如果已经加载,直接返回 this。

如果没有加载过,会取所有的参数,并将 this 放在第一个。优先执行 plugin.install 方法,若不能执行,则直接执行 plugin 自身。

最后将 plugin push 到插件列表中。

那么我们就需要看 VueRouter 的 install 方法做了什么,VueRouter 类定义在 src/index.js 文件中。

利用 vue 的插件机制,加载 vue-router

入口文件 index.js 对外 export 了一个 VueRouter 类。VueRouter 类包含了 router 的各种方法,我们直接先来看一下 install 方法。

install 方法在 index.js 中绑定在 VueRouter 类上:

import { install } from './install'
VueRouter.install = install

它的实际实现是在 ./install.js 中,install 方法主要做了以下几个事情:

1、设置了两个 mixin:beforeCreate 和 destroyed。

Vue.mixin({
 beforeCreate () {
  if (isDef(this.$options.router)) {
   this._routerRoot = this
   this._router = this.$options.router
   this._router.init(this)
   Vue.util.defineReactive(this, '_route', this._router.history.current)
  } else {
   this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
  }
  registerInstance(this, this)
 },
 destroyed () {
  registerInstance(this)
 }
})

2、在 Vue 上绑定 $route 和 $router。

Object.defineProperty(Vue.prototype, '$router', {
 get () { return this._routerRoot._router }
})

Object.defineProperty(Vue.prototype, '$route', {
 get () { return this._routerRoot._route }
})

3、注册两个组件,View 和 Link。

Vue.component('RouterView', View)
Vue.component('RouterLink', Link)

4、设置 beforeRouteEnter、beforeRouteLeave 和 beforeRouteUpdate 的 merge 策略。merge 策略的介绍可以见 这里 ,简单来说就是有重复的值时如何合并。

const strats = Vue.config.optionMergeStrategies
// use the same hook merging strategy for route hooks
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created

实例化 VueRouter

我们来看一下 VueRouter 的构造函数。首先,constructor 会初始化一些属性:

this.app = null
this.apps = []
this.options = options
this.beforeHooks = []
this.resolveHooks = []
this.afterHooks = []
this.matcher = createMatcher(options.routes || [], this)

其中 matcher 比较重要,后面会详细说。

之后会决定使用哪种模式:

let mode = options.mode || 'hash'
this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false
if (this.fallback) {
 mode = 'hash'
}
if (!inBrowser) {
 mode = 'abstract'
}
this.mode = mode

switch (mode) {
 case 'history':
  this.history = new HTML5History(this, options.base)
  break
 case 'hash':
  this.history = new HashHistory(this, options.base, this.fallback)
  break
 case 'abstract':
  this.history = new AbstractHistory(this, options.base)
  break
 default:
  if (process.env.NODE_ENV !== 'production') {
   assert(false, `invalid mode: ${mode}`)
  }
}

由于 history 模式中的pushstate方法还有一些浏览器没有支持。history 模式在浏览器不支持时会回退到hash模式。

之后根据不同模式选择实例化不同模式的history类,可以看到 hash 模式和 history 模式分别对应了 HashHistory 和 HTML5History 两个类。

此外,如果是服务器端渲染,需要进行 router 匹配来获取要渲染的页面。此时服务器环境中没有history api,因此要自行抽象实现一个,就是 AbstractHistory。

实例化 Vue

实例化为Vue 类时,会将 VueRouter 的实例传入,这个变量放在 this.$options.router 中。由于 vue router 时以插件形式引入的,因此 这个 this.$options.router 还是给 vue router 自身来用的。

vue router 初始化所做的事情就是这些,下篇博客我们来一起看一下 vue router 实际运行时发生了什么。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
window.location和document.location的区别分析
Dec 23 Javascript
jquery高级编程的最佳实践详解
Mar 23 Javascript
jQuery在ul中显示某个li索引号的方法
Mar 17 Javascript
jQuery实现为控件添加水印文字效果(附源码)
Dec 02 Javascript
Sublime Text 3常用插件及安装方法
Dec 16 Javascript
Angularjs实现多个页面共享数据的方式
Mar 29 Javascript
JavaScript仿网易选项卡制作代码
Oct 06 Javascript
js调用父框架函数与弹窗调用父页面函数的简单方法
Nov 01 Javascript
整理关于Bootstrap排版的慕课笔记
Mar 29 Javascript
使用vue-cli导入Element UI组件的方法
May 16 Javascript
Vue + Element UI图片上传控件使用详解
Aug 20 Javascript
node.JS二进制操作模块buffer对象使用方法详解
Feb 06 Javascript
node中间层实现文件上传功能
Jun 11 #Javascript
几个你不知道的技巧助你写出更优雅的vue.js代码
Jun 11 #Javascript
Vue.js 中取得后台原生HTML字符串 原样显示问题的解决方法
Jun 10 #Javascript
实例详解Node.js 函数
Jun 10 #Javascript
微信小程序实现倒计时调用相机自动拍照功能
Jun 10 #Javascript
深入浅析Vue中的Prop
Jun 10 #Javascript
vue项目部署上线遇到的问题及解决方法
Jun 10 #Javascript
You might like
PHP5中的this,self和parent关键字详解教程
2007/03/19 PHP
使用PHP求两个文件的相对路径
2013/06/20 PHP
php-perl哈希算法实现(times33哈希算法)
2013/12/30 PHP
PHP版本如何选择?应该使用哪个版本?
2015/05/13 PHP
实现PHP中session存储及删除变量
2018/10/15 PHP
js中top/parent/frame概述及案例应用
2013/02/06 Javascript
javascript不同类型数据之间的运算的转换方法
2014/02/13 Javascript
javascript中局部变量和全局变量的区别详解
2015/02/27 Javascript
JQuery中serialize() 序列化
2015/03/13 Javascript
jquery+css实现的红色线条横向二级菜单效果
2015/08/22 Javascript
JavaScript使用ZeroClipboard操作剪切板
2017/05/10 Javascript
Jquery中attr与prop的区别详解
2017/05/27 jQuery
详解react-router4 异步加载路由两种方法
2017/09/12 Javascript
微信小程序使用image组件显示图片的方法【附源码下载】
2017/12/08 Javascript
JS学习笔记之数组去重实现方法小结
2019/05/29 Javascript
深入理解令牌认证机制(token)
2019/08/22 Javascript
如何通过JS实现转码与解码
2020/02/21 Javascript
详解JavaScript中分解数字的三种方法
2021/01/05 Javascript
Python实现快速多线程ping的方法
2015/07/15 Python
Python 实现一个颜色色值转换的小工具
2016/12/06 Python
Python实现利用163邮箱远程关电脑脚本
2018/02/22 Python
pandas修改DataFrame列名的方法
2018/04/08 Python
Python os.access()用法实例
2019/02/18 Python
python游戏开发之视频转彩色字符动画
2019/04/26 Python
pygame实现俄罗斯方块游戏(对战篇1)
2019/10/29 Python
Python 实现日志同时输出到屏幕和文件
2020/02/19 Python
利用Python实现Json序列化库的方法步骤
2020/09/09 Python
通过Canvas及File API缩放并上传图片完整示例
2013/08/08 HTML / CSS
世界领先的电子书网站:eBooks.com(在线购买小说、非小说和教科书)
2019/03/30 全球购物
linux面试题参考答案(9)
2015/01/07 面试题
大学生毕业自荐信
2013/10/10 职场文书
元旦促销方案
2014/03/15 职场文书
运动会报道稿300字
2014/10/02 职场文书
详解MySQL集群搭建
2021/05/26 MySQL
Pytorch 如何实现常用正则化
2021/05/27 Python
Python 类,对象,数据分类,函数参数传递详解
2021/09/25 Python