详解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 相关文章推荐
javascript获取当前日期时间及其它操作函数
Jan 11 Javascript
js实现杯子倒水问题自动求解程序
Mar 25 Javascript
jquery中插件实现自动添加用户的具体代码
Nov 15 Javascript
JavaScript字符串对象toLowerCase方法入门实例(用于把字母转换为小写)
Oct 17 Javascript
鼠标事件的screenY,pageY,clientY,layerY,offsetY属性详解
Mar 12 Javascript
过期软件破解办法实例详解
Jan 04 Javascript
在 Angular2 中实现自定义校验指令(确认密码)的方法
Jan 23 Javascript
分享一道关于闭包、bind和this的面试题
Feb 20 Javascript
jquery插件ContextMenu设置右键菜单
Mar 13 Javascript
Three.js利用性能插件stats实现性能监听的方法
Sep 25 Javascript
vue富文本编辑器组件vue-quill-edit使用教程
Sep 21 Javascript
node.js调用C++函数的方法示例
Sep 21 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
第三节 定义一个类 [3]
2006/10/09 PHP
Yii查询生成器(Query Builder)用法实例教程
2014/09/04 PHP
PHP数组生成XML格式数据的封装类实例
2016/11/10 PHP
禁止刷新,回退的JS
2006/11/25 Javascript
上传的js验证(图片/文件的扩展名)
2013/04/25 Javascript
jQuery实现购物车计算价格功能的方法
2015/03/25 Javascript
js实现简单的左右两边固定广告效果实例
2015/04/10 Javascript
10条建议帮助你创建更好的jQuery插件
2015/05/18 Javascript
关于javascript中dataset的问题小结
2015/11/16 Javascript
基于jQuery 实现bootstrapValidator下的全局验证
2015/12/07 Javascript
jQuery对checkbox 复选框的全选全不选反选的操作
2016/08/09 Javascript
解析Vue2.0双向绑定实现原理
2017/02/23 Javascript
self.attachevent is not a function的解决方法
2017/04/04 Javascript
JavaScript实现form表单的多文件上传
2020/03/27 Javascript
AngularJS基于http请求实现下载php生成的excel文件功能示例
2018/01/23 Javascript
重学 JS:为啥 await 不能用在 forEach 中详解
2019/04/15 Javascript
vuex(vue状态管理)的特殊应用案例分享
2020/03/03 Javascript
javascript中正则表达式语法详解
2020/08/07 Javascript
[41:54]2018DOTA2亚洲邀请赛 4.1 小组赛A组加赛 TNC vs Liquid
2018/04/03 DOTA
[01:19:46]DOTA2-DPC中国联赛 正赛 SAG vs DLG BO3 第一场 2月28日
2021/03/11 DOTA
解决Pytorch 训练与测试时爆显存(out of memory)的问题
2019/08/20 Python
python多线程使用方法实例详解
2019/12/30 Python
Python3标准库之functools管理函数的工具详解
2020/02/27 Python
Django User 模块之 AbstractUser 扩展详解
2020/03/11 Python
意大利奢侈品网站:Italist
2016/08/23 全球购物
Foot Locker意大利官网:全球领先的运动鞋和服装零售商
2017/05/30 全球购物
宿舍打麻将检讨书
2014/01/24 职场文书
医药类个人求职的自我评价
2014/02/12 职场文书
棉花姑娘教学反思
2014/02/15 职场文书
党的群众路线教育实践活动心得体会
2014/03/03 职场文书
学习十八大标语
2014/10/09 职场文书
《家世》读后感:看家训的力量
2019/12/30 职场文书
php引用传递
2021/04/01 PHP
MySQL深度分页(千万级数据量如何快速分页)
2021/07/25 MySQL
一篇文章弄懂Python中的内建函数
2021/08/07 Python
uniapp引入支付宝原生扫码插件步骤详解
2022/07/23 Javascript