详解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 08 Javascript
js自调用匿名函数的三种写法(推荐)
Aug 19 Javascript
jQuery实现的网页换肤效果示例
Sep 20 Javascript
angular实现表单验证及提交功能
Feb 01 Javascript
文本溢出插件jquery.dotdotdot.js使用方法详解
Jun 22 jQuery
微信小程序 跳转传递数据的实例
Jul 06 Javascript
JS脚本实现网页自动秒杀点击
Jan 11 Javascript
Spring Boot/VUE中路由传递参数的实现代码
Mar 02 Javascript
jQuery实现的点击标题文字切换字体效果示例【测试可用】
Apr 26 jQuery
element-ui使用导航栏跳转路由的用法详解
Aug 22 Javascript
elementUI 设置input的只读或禁用的方法
Oct 30 Javascript
通过cordova将vue项目打包为webapp的方法
Feb 02 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设计模式 Bridge (桥接模式)
2011/06/26 PHP
注册页面之前先验证用户名是否存在的php代码
2012/07/14 PHP
php判断字符串在另一个字符串位置的方法
2014/02/27 PHP
ThinkPHP之用户注册登录留言完整实例
2014/07/22 PHP
PHP高级编程实例:编写守护进程
2014/09/02 PHP
PHPExcel笔记, mpdf导出
2016/05/03 PHP
js中的前绑定和后绑定详解
2013/08/01 Javascript
jquery属性选择器not has怎么写 行悬停高亮显示
2013/11/13 Javascript
JS实现网页右侧带动画效果的伸缩窗口代码
2015/10/29 Javascript
AngularJS入门之动画
2016/07/27 Javascript
Angular的自定义指令以及实例
2016/12/26 Javascript
微信小程序开发入门基础教程
2017/04/19 Javascript
JS中跳出循环的示例代码
2017/09/14 Javascript
angularjs 获取默认选中的单选按钮的value方法
2018/02/28 Javascript
vue-cli2.0转3.0之项目搭建的详细步骤
2018/12/11 Javascript
vue移动端屏幕适配详解
2019/04/30 Javascript
仿iPhone通讯录制作小程序自定义选择组件的实现
2019/05/23 Javascript
基于layui的下拉列表的数据回显方法
2019/09/24 Javascript
vue中音频wavesurfer.js的使用方法
2020/02/20 Vue.js
如何基于viewport vm适配移动端页面
2020/11/13 Javascript
Python实现登录接口的示例代码
2017/07/21 Python
Python使用装饰器模拟用户登陆验证功能示例
2018/08/24 Python
django主动抛出403异常的方法详解
2019/01/04 Python
python数据预处理之数据标准化的几种处理方式
2019/07/17 Python
python关于变量名的基础知识点
2020/03/03 Python
CSS3属性background-size使用指南
2014/12/09 HTML / CSS
世界上最好的足球商店:Unisport
2019/03/02 全球购物
工厂门卫岗位职责
2013/11/25 职场文书
高中数学教学反思
2014/01/30 职场文书
群众路线批评与自我批评
2014/02/06 职场文书
教师岗位聘任书范文
2014/03/29 职场文书
考试作弊检讨书怎么写?
2014/12/21 职场文书
投标邀请书范本
2015/02/02 职场文书
针对吵架老公保证书
2015/05/08 职场文书
golang switch语句的灵活写法介绍
2021/05/06 Golang
vue点击弹窗自动触发点击事件的解决办法(模拟场景)
2021/05/25 Vue.js