详解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 Base64编码和解码,实现URL参数传递。
Sep 18 Javascript
用Javscript实现表单复选框的全选功能
May 25 Javascript
基于jquery创建的一个图片、视频缓冲的效果样式插件
Aug 28 Javascript
ExtJS中文乱码之GBK格式编码解决方案及代码
Jan 20 Javascript
jquery 按钮状态效果 正常、移上、按下
Aug 12 Javascript
javascript实现简单的分页特效
Aug 12 Javascript
Boostrap实现的登录界面实例代码
Oct 09 Javascript
JavaScript表单验证开发
Nov 23 Javascript
详解vue.js全局组件和局部组件
Apr 10 Javascript
layerUI下的绑定事件实例代码
Aug 17 Javascript
layer弹出层取消遮罩的方法
Sep 25 Javascript
JavaScript中while循环的基础使用教程
Aug 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配置心得包含MYSQL5乱码解决
2006/11/20 PHP
PHP如何得到当前页和上一页的地址?
2006/11/27 PHP
Apache环境下PHP利用HTTP缓存协议原理解析及应用分析
2010/02/16 PHP
PHP实现的网站目录扫描索引工具
2016/09/08 PHP
visual studio code 调试php方法(图文详解)
2017/09/15 PHP
PHP获取数组中指定的一列实例
2017/12/27 PHP
一文掌握PHP Xdebug 本地与远程调试(小结)
2019/04/23 PHP
使用JavaScript实现Java的List功能(实例讲解)
2013/11/07 Javascript
javascript 中that的含义示例介绍
2014/05/14 Javascript
javascript实现禁止复制网页内容
2014/12/16 Javascript
对比分析AngularJS中的$http.post与jQuery.post的区别
2015/02/27 Javascript
在Node.js应用中读写Redis数据库的简单方法
2015/06/30 Javascript
javascript实现加载xml文件的方法
2015/11/24 Javascript
在Html中使用Requirejs进行模块化开发实例详解
2016/04/15 Javascript
jQuery实现右键菜单、遮罩等效果代码
2016/09/27 Javascript
node实现简单的反向代理服务器
2017/07/26 Javascript
React Native时间转换格式工具类分享
2017/10/24 Javascript
node 利用进程通信实现Cluster共享内存
2017/10/27 Javascript
在Mac下彻底卸载node和npm的方法
2018/05/16 Javascript
vue-simple-uploader上传成功之后的response获取代码
2020/09/07 Javascript
vue 实现基础组件的自动化全局注册
2020/12/25 Vue.js
Python中正则表达式的用法实例汇总
2014/08/18 Python
Python3内置模块之json编解码方法小结【推荐】
2020/12/09 Python
python二维码操作:对QRCode和MyQR入门详解
2019/06/24 Python
django云端留言板实例详解
2019/07/22 Python
使用OpCode绕过Python沙箱的方法详解
2019/09/03 Python
django序列化serializers过程解析
2019/12/14 Python
pymysql 插入数据 转义处理方式
2020/03/02 Python
python模拟实现分发扑克牌
2020/04/22 Python
python性能测试工具locust的使用
2020/12/28 Python
html5实现微信打飞机游戏
2014/03/27 HTML / CSS
企业厂长岗位职责
2013/12/17 职场文书
电子工程专业毕业生求职信
2014/03/14 职场文书
保卫钓鱼岛口号
2014/06/20 职场文书
公司人力资源管理制度
2015/08/05 职场文书
分析SQL窗口函数之聚合窗口函数
2022/04/21 Oracle