详解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 相关文章推荐
(currentStyle)javascript为何有时用style得不到已设定的CSS的属性
Aug 15 Javascript
JavaScript 学习笔记(十五)
Jan 28 Javascript
JQuery UI的拖拽功能实现方法小结
Mar 14 Javascript
JavaScript中双叹号(!!)作用示例介绍
Apr 10 Javascript
如何获取网站icon有哪些可行的方法
Jun 05 Javascript
jQuery实现简单的文件上传进度条效果
Mar 26 Javascript
基于jquery实现智能提示控件intellSeach.js
Mar 17 Javascript
详解堆的javascript实现方法
Nov 29 Javascript
JavaScript实现星星等级评价功能
Mar 22 Javascript
js事件委托和事件代理案例分享
Jul 25 Javascript
jQuery中each方法的使用详解
Mar 18 jQuery
inquirer.js一个用户与命令行交互的工具详解
May 18 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
用Socket发送电子邮件(利用需要验证的SMTP服务器)
2006/10/09 PHP
PHP实现的函数重载功能示例
2018/08/03 PHP
PHP asXML()函数讲解
2019/02/03 PHP
微信JSSDK分享功能图文实例详解
2019/04/08 PHP
laravel自定义分页的实现案例offset()和limit()
2019/10/15 PHP
javascript replace()正则替换实现代码
2010/02/26 Javascript
getAsDataURL在Firefox7.0下无法预览本地图片的解决方法
2013/11/15 Javascript
简介JavaScript中的getSeconds()方法的使用
2015/06/10 Javascript
jQuery实现平滑滚动页面到指定锚点链接的方法
2015/07/15 Javascript
Javascript闭包实例详解
2015/11/29 Javascript
JavaScript+html5 canvas绘制渐变区域完整实例
2016/01/26 Javascript
jQuery实现智能判断固定导航条或侧边栏的方法
2016/09/04 Javascript
JavaScript学习笔记--常用的互动方法
2016/12/07 Javascript
Node连接mysql数据库方法介绍
2017/02/07 Javascript
Electron vue的使用教程图文详解
2019/07/05 Javascript
浅析vue-router中params和query的区别
2019/12/24 Javascript
JS使用setInterval计时器实现挑战10秒
2020/11/08 Javascript
学习python的几条建议分享
2013/02/10 Python
Django集成百度富文本编辑器uEditor攻略
2014/07/04 Python
编写简单的Python程序来判断文本的语种
2015/04/07 Python
python对指定目录下文件进行批量重命名的方法
2015/04/18 Python
Python三级目录展示的实现方法
2016/09/28 Python
python实现AES和RSA加解密的方法
2019/03/28 Python
pymysql模块的操作实例
2019/12/17 Python
Python环境使用OpenCV检测人脸实现教程
2020/10/19 Python
CSS3模块的目前的状况分析
2010/02/24 HTML / CSS
html5拖拽应用记录及注意点
2020/05/27 HTML / CSS
澳大利亚领先的在线机械五金、园艺和存储专家:Edisons
2018/03/24 全球购物
高清安全摄像头系统:Lorex Technology
2018/07/20 全球购物
GWT的应用有哪两种部署模式
2012/12/21 面试题
建筑专业自荐信范文
2014/01/05 职场文书
2014小学教师个人工作总结
2014/11/10 职场文书
辞职信的写法
2015/02/27 职场文书
2016大一新生入学教育心得体会
2016/01/23 职场文书
Python使用UDP实现720p视频传输的操作
2021/04/24 Python
用python批量解压带密码的压缩包
2021/05/31 Python