详解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闭包的高级使用方法实例
Jul 04 Javascript
jQuery中RadioButtonList的功能及用法实例介绍
Aug 23 Javascript
js 高效去除数组重复元素示例代码
Dec 19 Javascript
Clipboard.js 无需Flash的JavaScript复制粘贴库
Oct 02 Javascript
JavaScript闭包实例详解
Jun 03 Javascript
Vue.js第三天学习笔记(计算属性computed)
Dec 01 Javascript
JavaScript常见的五种数组去重的方式
Dec 15 Javascript
JS正则验证多个邮箱完整实例【邮箱用分号隔开】
Apr 19 Javascript
解决vue热替换失效的根本原因
Sep 19 Javascript
angularjs模态框的使用代码实例
Dec 20 Javascript
ES6使用 Array.includes 处理多重条件用法实例分析
Mar 02 Javascript
vue mvvm数据响应实现
Nov 11 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
PHP的cURL库功能简介 抓取网页、POST数据及其他
2011/04/07 PHP
ini_set的用法介绍
2014/01/07 PHP
PHP中类属性与类静态变量的访问方法示例
2016/07/13 PHP
PHP PDOStatement::bindValue讲解
2019/01/30 PHP
php异常处理捕获错误整理
2019/09/23 PHP
JavaScript replace(rgExp,fn)正则替换的用法
2010/03/04 Javascript
js中function()使用方法
2013/12/24 Javascript
javascript实现禁止复制网页内容汇总
2015/12/30 Javascript
JS常见问题之为什么点击弹出的i总是最后一个
2016/01/05 Javascript
关于Jquery中的事件绑定总结
2016/10/26 Javascript
浅谈js函数三种定义方式 & 四种调用方式 & 调用顺序
2017/02/19 Javascript
详解VUE 数组更新
2017/12/16 Javascript
VUE 组件转换为微信小程序组件的方法
2019/11/06 Javascript
Openlayers绘制地图标注
2020/09/28 Javascript
js异步接口并发数量控制的方法示例
2020/11/22 Javascript
Python 列表(List)操作方法详解
2014/03/11 Python
Python实现八皇后问题示例代码
2018/12/09 Python
python3 小数位的四舍五入(用两种方法解决round 遇5不进)
2019/04/11 Python
python实现接口并发测试脚本
2019/06/25 Python
pybind11在Windows下的使用教程
2019/07/04 Python
Python笔记之工厂模式
2019/11/20 Python
Django对接支付宝实现支付宝充值金币功能示例
2019/12/17 Python
python 读取更新中的log 或其它文本方式
2019/12/24 Python
pycharm 中mark directory as exclude的用法详解
2020/02/14 Python
使用css3制作登录表单的步骤
2014/04/07 HTML / CSS
HTML5 video 视频标签使用介绍
2014/02/03 HTML / CSS
Html5 new XMLHttpRequest()监听附件上传进度
2021/01/14 HTML / CSS
波兰化妆品和护肤品购物网站:eKobieca
2019/08/30 全球购物
数据库连接池的工作原理
2012/09/26 面试题
新闻编辑专业毕业自荐书范文
2014/02/05 职场文书
出纳员岗位责任制
2014/02/11 职场文书
物流管理专业自荐信
2014/06/23 职场文书
国家机关领导干部民主生活会对照检查材料思想汇报
2014/09/17 职场文书
慰问信模板
2015/02/14 职场文书
php随机生成验证码,php随机生成数字,php随机生成数字加字母!
2021/04/01 PHP
javascript数组includes、reduce的基本使用
2021/07/02 Javascript