详解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 相关文章推荐
如何在标题栏显示框架内页面的标题
Feb 03 Javascript
学习ExtJS Window常用方法
Oct 07 Javascript
Fixie.js 自动填充内容的插件
Jun 28 Javascript
页面刷新时记住滚动条的位置jquery代码
Jun 17 Javascript
3种Jquery限制文本框只能输入数字字母的方法
Dec 03 Javascript
JS简单实现数组去重的方法示例
Mar 27 Javascript
JavaScript中的return布尔值的用法和原理解析
Aug 14 Javascript
详解动画插件wow.js的使用方法
Sep 13 Javascript
angular2实现统一的http请求头方法
Aug 13 Javascript
实例详解vue中的$root和$parent
Apr 29 Javascript
BootStrap前端框架使用方法详解
Feb 26 Javascript
vue实现倒计时功能
Mar 24 Vue.js
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
JoshChen_php新手进阶高手不可或缺的规范介绍
2013/08/16 PHP
使用Discuz关键词服务器实现PHP中文分词
2014/03/11 PHP
php提取字符串中网站url地址的方法
2014/12/03 PHP
PHP中$_SERVER使用说明
2015/07/05 PHP
PHP+Jquery与ajax相结合实现下拉淡出瀑布流效果【无需插件】
2016/05/06 PHP
Smarty简单生成表单元素的方法示例
2016/05/23 PHP
php-fpm服务启动脚本的方法
2018/04/27 PHP
一段非常简单的让图片自动切换js代码
2006/11/10 Javascript
js验证表单大全
2006/11/25 Javascript
北京奥运官方网站幻灯切换效果flash版打包下载
2008/01/30 Javascript
JavaScript fontcolor方法入门实例(按照指定的颜色来显示字符串)
2014/10/17 Javascript
PHP中CURL的几个经典应用实例
2015/01/23 Javascript
实例讲解jQuery中对事件的命名空间的运用
2016/05/24 Javascript
浅谈js图片前端预览之filereader和window.URL.createObjectURL
2016/06/30 Javascript
jQuery实现的兼容性浮动层示例
2016/08/02 Javascript
解析Javascript单例模式概念与实例
2016/12/05 Javascript
想学习javascript JS和jQuery哪个重要 先学哪个
2016/12/11 Javascript
jQuery实现遮罩层登录对话框
2016/12/29 Javascript
js鼠标移动时禁止选中文字
2017/02/19 Javascript
React-Router如何进行页面权限管理的方法
2017/12/06 Javascript
详解Node.js模板引擎Jade入门
2018/01/19 Javascript
Python实现生成随机数据插入mysql数据库的方法
2017/12/25 Python
基于Python实现的微信好友数据分析
2018/02/26 Python
python基于C/S模式实现聊天室功能
2019/01/09 Python
python程序 创建多线程过程详解
2019/09/23 Python
django-利用session机制实现唯一登录的例子
2020/03/16 Python
python将logging模块封装成单独模块并实现动态切换Level方式
2020/05/12 Python
Python如何读取、写入CSV数据
2020/07/28 Python
python获取百度热榜链接的实例方法
2020/08/25 Python
python 监控服务器是否有人远程登录(详细思路+代码)
2020/12/18 Python
世界汽车零件:World Car Parts
2019/09/04 全球购物
J2EE相关知识面试题
2013/08/26 面试题
办公室打字员岗位职责
2014/04/16 职场文书
经营理念口号
2014/06/21 职场文书
Python中tkinter的用户登录管理的实现
2021/04/22 Python
pytorch实现加载保存查看checkpoint文件
2022/07/15 Python