vue-router源码之history类的浅析


Posted in Javascript onMay 21, 2019

当前版本: 3.0.3

类目录: src/history/base.js

前言:

对于vue-router来说,有三种路由模式history,hash,abstract, abstract是运行在没有window的环境下的,这三种模式都是继承于history类,history实现了一些共用的方法,对于一开始看vue-router源码来说,可以从这里开始看起。

初始属性

router: Router; 表示VueRouter实例。实例化History类时的第一个参数
 base: string;  表示基路径。会用normalizeBase进行规范化。实例化History类时的第二个参数。
 current: Route; 表示当前路由(route)。
 pending: ?Route; 描述阻塞状态。
 cb: (r: Route) => void; 监听时的回调函数。
 ready: boolean; 描述就绪状态。
 readyCbs: Array<Function>; 就绪状态的回调数组。
 readyErrorCbs: Array<Function>; 就绪时产生错误的回调数组。
 errorCbs: Array<Function>; 错误的回调数组

 // implemented by sub-classes
 <!-- 下面几个是需要子类实现的方法,这里就先不说了,之后写其他类实现的时候分析 -->
 +go: (n: number) => void;
 +push: (loc: RawLocation) => void;
 +replace: (loc: RawLocation) => void;
 +ensureURL: (push?: boolean) => void;
 +getCurrentLocation: () => string;

对于history类来说,主要是下下面两个函数的逻辑

transitionTo

这个方法主要是对路由跳转的封装, location接收的是HTML5History,HashHistory,AbstractHistory, onComplete是成功的回调,onAbort是失败的回调

transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
  const route = this.router.match(location, this.current) // 解析成每一个location需要的route
  this.confirmTransition(route, () => {
   this.updateRoute(route)
   onComplete && onComplete(route)
   this.ensureURL()

   // fire ready cbs once
   if (!this.ready) {
    this.ready = true
    this.readyCbs.forEach(cb => { cb(route) })
   }
  }, err => {
   if (onAbort) {
    onAbort(err)
   }
   if (err && !this.ready) {
    this.ready = true
    this.readyErrorCbs.forEach(cb => { cb(err) })
   }
  })
 }

confirmTransition

这是方法是确认跳转,route是匹配的路由对象, onComplete是匹配成功的回调, 是匹配失败的回调

confirmTransition(route: Route, onComplete: Function, onAbort?: Function) {
    const current = this.current
    const abort = err => { // 异常处理函数
      if (isError(err)) {
        if (this.errorCbs.length) {
          this.errorCbs.forEach(cb => { cb(err) })
        } else {
          warn(false, 'uncaught error during route navigation:')
          console.error(err)
        }
      }
      onAbort && onAbort(err)
    }
    if (
      isSameRoute(route, current) &&
      // in the case the route map has been dynamically appended to
      route.matched.length === current.matched.length
    ) {
      this.ensureURL()
      return abort()
    }
    <!-- 根据当前路由对象和匹配的路由:返回更新的路由、激活的路由、停用的路由 -->
    const {
      updated,
      deactivated,
      activated
    } = resolveQueue(this.current.matched, route.matched)
    <!-- 需要执行的任务队列 -->
    const queue: Array<?NavigationGuard> = [].concat(
      // beforeRouteLeave 钩子函数
      extractLeaveGuards(deactivated),
      // 全局的beforeHooks勾子
      this.router.beforeHooks,
      // beforeRouteUpdate 钩子函数调用
      extractUpdateHooks(updated),
      // config里的勾子
      activated.map(m => m.beforeEnter),
      // async components
      resolveAsyncComponents(activated)
    )
    
    this.pending = route
    <!-- 对于queue数组所执行的迭代器方法 -->
    const iterator = (hook: NavigationGuard, next) => {
      if (this.pending !== route) {
        return abort()
      }
      try {
        hook(route, current, (to: any) => {
          if (to === false || isError(to)) {
            // next(false) -> abort navigation, ensure current URL
            this.ensureURL(true)
            abort(to)
          } else if (
            typeof to === 'string' ||
            (typeof to === 'object' && (
              typeof to.path === 'string' ||
              typeof to.name === 'string'
            ))
          ) {
            // next('/') or next({ path: '/' }) -> redirect
            abort()
            if (typeof to === 'object' && to.replace) {
              this.replace(to)
            } else {
              this.push(to)
            }
          } else {
            // confirm transition and pass on the value
            next(to)
          }
        })
      } catch (e) {
        abort(e)
      }
    }
    
    runQueue(queue, iterator, () => {
      const postEnterCbs = []
      const isValid = () => this.current === route
      <!-- beforeRouteEnter 钩子函数调用 -->
      const enterGuards = extractEnterGuards(activated, postEnterCbs, isValid)
      const queue = enterGuards.concat(this.router.resolveHooks)
      <!-- 迭代运行queue -->
      runQueue(queue, iterator, () => {
        if (this.pending !== route) {
          return abort()
        }
        this.pending = null
        onComplete(route)
        if (this.router.app) {
          this.router.app.$nextTick(() => {
            postEnterCbs.forEach(cb => { cb() })
          })
        }
      })
    })
  }

结语:

每一次总结,都是对之前读源码的再一次深入的了解

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery 行背景颜色的交替显示(隔行变色)实现代码
Dec 13 Javascript
jQuery Select(单选) 模拟插件 V1.3.62 改进版
Jul 17 Javascript
JavaScript 模式之工厂模式(Factory)应用介绍
Nov 15 Javascript
require.js深入了解 require.js特性介绍
Sep 04 Javascript
jQuery中focus事件用法实例
Dec 26 Javascript
javascript中setInterval的用法
Jul 19 Javascript
深入学习JavaScript对象
Oct 13 Javascript
微信小程序 五星评分(包括半颗星评分)实例代码
Dec 14 Javascript
vue源码解析之事件机制原理
Apr 21 Javascript
jQuery ajax仿Google自动提示SearchSuggess功能示例
Mar 28 jQuery
JS浏览器BOM常见操作实例详解
Apr 27 Javascript
google广告之另类js调用实现代码
Aug 22 Javascript
vue 地图可视化 maptalks 篇实例代码详解
May 21 #Javascript
vue 中使用 watch 出现了如下的报错的原因分析
May 21 #Javascript
Node.js 获取微信JS-SDK CONFIG的方法示例
May 21 #Javascript
vue+element创建动态的form表单及动态生成表格的行和列
May 20 #Javascript
Node 搭建一个静态资源服务器的实现
May 20 #Javascript
vue+element实现打印页面功能
May 20 #Javascript
vue+element实现表单校验功能
May 20 #Javascript
You might like
用php写的serv-u的web申请账号的程序
2006/10/09 PHP
php-accelerator网站加速PHP缓冲的方法
2008/07/30 PHP
php 正则匹配函数体
2009/08/25 PHP
PHP获取文件相对路径的方法
2015/02/26 PHP
PHP的Yii框架中YiiBase入口类的扩展写法示例
2016/03/17 PHP
基于JQuery实现相同内容合并单元格的代码
2011/01/12 Javascript
理清apply(),call()的区别和关系
2011/08/14 Javascript
js验证整数加保留小数点的简单实例
2013/12/02 Javascript
图片放大镜jquery.jqzoom.js使用实例附放大镜图标
2014/06/19 Javascript
JQuery 给元素绑定click事件多次执行的解决方法
2014/09/09 Javascript
Jquery实现textarea根据文本内容自适应高度
2015/04/03 Javascript
js实现表单检测及表单提示的方法
2015/08/14 Javascript
BootStrap+Angularjs+NgDialog实现模式对话框
2016/08/24 Javascript
js select实现省市区联动选择
2020/04/17 Javascript
深入理解React中es6创建组件this的方法
2016/08/29 Javascript
javascript中replace使用方法总结
2017/03/01 Javascript
JS 组件系列之Bootstrap Table 冻结列功能IE浏览器兼容性问题解决方案
2017/06/30 Javascript
用vue封装插件并发布到npm的方法步骤
2017/10/18 Javascript
TypeScript基础入门教程之三重斜线指令详解
2018/10/22 Javascript
三分钟教你用Node做一个微信哄女友(基友)神器(面向小白)
2019/06/21 Javascript
详解javascript void(0)
2020/07/13 Javascript
Python实现CET查分的方法
2015/03/10 Python
python中使用序列的方法
2015/08/03 Python
Python计时相关操作详解【time,datetime】
2017/05/26 Python
python利用正则表达式搜索单词示例代码
2017/09/24 Python
Tensorflow实现卷积神经网络的详细代码
2018/05/24 Python
python opencv实现切变换 不裁减图片
2018/07/26 Python
Python用字典构建多级菜单功能
2019/07/11 Python
python logging日志模块原理及操作解析
2019/10/12 Python
Python结合Window计划任务监测邮件的示例代码
2020/08/05 Python
银行柜员应聘推荐信范文
2013/11/24 职场文书
2014年国培研修感言
2014/03/09 职场文书
《周恩来的四个昼夜》观后思想汇报范文两篇
2014/09/10 职场文书
大学感恩节活动总结
2015/05/05 职场文书
民事撤诉申请书范本
2015/05/18 职场文书
元旦晚会开场白
2015/05/29 职场文书