详解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语言结构小记(一)
Sep 10 Javascript
鼠标滑在标题上显示图片的JS代码
Nov 19 Javascript
js获取客户端外网ip的简单实例
Nov 21 Javascript
js的2种继承方式详解
Mar 04 Javascript
vue-dialog的弹出层组件
May 25 Javascript
vue2中filter()的实现代码
Jul 09 Javascript
Bootstrap一款超好用的前端框架
Sep 25 Javascript
cropper js基于vue的图片裁剪上传功能的实现代码
Mar 01 Javascript
微信小程序实现刷脸登录
May 25 Javascript
不得不知的ES6小技巧
Jul 28 Javascript
nuxt.js中间件实现拦截权限判断的方法
Nov 21 Javascript
vue实现短信验证码输入框
Apr 17 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学习散记_编码(json_encode 中文不显示)
2011/11/10 PHP
php 的加密函数 md5,crypt,base64_encode 等使用介绍
2012/04/09 PHP
ThinkPHP关于session的操作方法汇总
2014/07/18 PHP
ThinkPHP发送邮件示例代码
2016/10/08 PHP
PHP实现二维数组(或多维数组)转换成一维数组的常见方法总结
2019/12/04 PHP
PHP如何使用array_unshift()在数组开头插入元素
2020/09/01 PHP
利用腾讯的ip地址库做ip物理地址定位
2010/07/24 Javascript
select标记美化--JS式插件、后期加载
2013/04/01 Javascript
网站如何做到完全不需要jQuery也可以满足简单需求
2013/06/27 Javascript
JavaScript截取指定长度字符串点击可以展开全部代码
2015/12/04 Javascript
jQuery on()方法绑定动态元素的点击事件实例代码浅析
2016/06/16 Javascript
EasyUI加载完Html内容样式渲染完成后显示
2016/07/25 Javascript
js插件dropload上拉下滑加载数据实例解析
2016/07/27 Javascript
Bootstrap弹出框之自定义悬停框标题、内容和样式示例代码
2017/07/11 Javascript
使用vue制作FullPage页面滚动效果
2017/08/21 Javascript
bmob js-sdk 在vue中的使用教程
2018/01/21 Javascript
微信小程序中实现手指缩放图片的示例代码
2018/03/13 Javascript
vue.js使用v-pre与v-html输出HTML操作示例
2018/07/07 Javascript
快速解决angularJS中用post方法时后台拿不到值的问题
2018/08/14 Javascript
详解jQuery-each()方法
2019/03/13 jQuery
js实现拾色器插件(ColorPicker)
2020/05/21 Javascript
python启动应用程序和终止应用程序的方法
2019/06/28 Python
关于PyTorch源码解读之torchvision.models
2019/08/17 Python
python中下标和切片的使用方法解析
2019/08/27 Python
python字符串替换re.sub()方法解析
2019/09/18 Python
python实现数据结构中双向循环链表操作的示例
2020/10/09 Python
纯CSS3单页切换导航菜单界面设计的简单实现
2016/08/16 HTML / CSS
html5使用Drag事件编辑器拖拽上传图片的示例代码
2017/08/22 HTML / CSS
草莓网化妆品日本站:Strawberrynet日本
2017/10/20 全球购物
英国厨房与餐具用品为主的设计品牌:Joseph Joseph
2018/04/26 全球购物
Claire’s法国:时尚配饰、美容、珠宝、头发
2021/01/16 全球购物
高一物理教学反思
2014/01/24 职场文书
房屋登记授权委托书范本
2014/10/09 职场文书
食品药品安全责任书
2015/05/11 职场文书
Python爬虫中urllib3与urllib的区别是什么
2021/07/21 Python
Sql Server 行数据的某列值想作为字段列显示的方法
2022/04/20 SQL Server