详解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实现的支持lrc歌词的播放器
May 17 Javascript
收藏Javascript中常用的55个经典技巧
Aug 12 Javascript
基于jquery的一个简单的脚本验证插件
Apr 05 Javascript
jQuery学习笔记之控制页面实现代码
Feb 27 Javascript
关于jQuery判断元素是否存在的问题示例探讨
Jul 21 Javascript
javascript常见数据验证插件大全
Aug 03 Javascript
jQuery实现仿美橙互联两级导航菜单效果完整实例
Sep 17 Javascript
JQuery实现级联下拉框效果实例讲解
Sep 17 Javascript
jQuery多个版本和其他js库冲突的解决方法
Aug 11 Javascript
jquery uploadify隐藏上传进度的实现方法
Feb 06 Javascript
JavaScript栈和队列相关操作与实现方法详解
Dec 07 Javascript
解决在Vue中使用axios POST请求变成OPTIONS的问题
Aug 14 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中usort在值相同时改变原始位置问题的解决方法
2011/11/27 PHP
Thinkphp关闭缓存的方法
2015/06/26 PHP
PHP检查URL包含特定字符串实例方法
2019/02/11 PHP
总结一些js自定义的函数
2006/08/05 Javascript
关于js获取radio和select的属性并控制的代码
2011/05/12 Javascript
document.compatMode的CSS1compat使用介绍
2014/04/03 Javascript
DOM节点的替换或修改函数replaceChild()用法实例
2015/01/12 Javascript
js跨浏览器的事件侦听器和事件对象的使用方法
2015/12/17 Javascript
bootstrap modal弹出框的垂直居中
2016/12/14 Javascript
详解javascript表单的Ajax提交插件的使用
2016/12/29 Javascript
JS小数转换为整数的方法分析
2017/01/07 Javascript
vue.js+Element实现表格里的增删改查
2017/01/18 Javascript
js 监控iframe URL的变化实例代码
2017/07/12 Javascript
React Native使用fetch实现图片上传的示例代码
2018/03/07 Javascript
Vue 组件注册实例详解
2019/02/23 Javascript
Vue+Element UI+vue-quill-editor富文本编辑器及插入图片自定义
2019/08/20 Javascript
javascript实现抢购倒计时程序
2019/08/26 Javascript
vue实现select下拉显示隐藏功能
2019/09/30 Javascript
JavaScript使用prototype属性实现继承操作示例
2020/05/22 Javascript
python实现向ppt文件里插入新幻灯片页面的方法
2015/04/28 Python
5种Python单例模式的实现方式
2016/01/14 Python
Pycharm设置界面全黑的方法
2018/05/23 Python
python 获得任意路径下的文件及其根目录的方法
2019/02/16 Python
Python基于DB-API操作MySQL数据库过程解析
2020/04/23 Python
公认8个效率最高的爬虫框架
2020/07/28 Python
基于HTML5陀螺仪实现ofo首页眼睛移动效果的示例
2017/07/31 HTML / CSS
如何清空Session
2015/02/23 面试题
酒店销售经理岗位职责
2014/01/31 职场文书
《玩具柜台前的孩子》教学反思
2014/02/13 职场文书
法院先进个人事迹材料
2014/05/04 职场文书
航空学院求职信
2014/06/11 职场文书
教师自我剖析材料(群众路线)
2014/09/29 职场文书
万里长城导游词
2015/01/30 职场文书
PHP基本语法
2021/03/31 PHP
一篇文章弄懂MySQL查询语句的执行过程
2021/05/07 MySQL
MySQL命令无法输入中文问题的解决方式
2021/08/30 MySQL