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 相关文章推荐
javascript 动态table添加colspan\rowspan 参数的方法
Jul 25 Javascript
javascript 多级checkbox选择效果
Aug 20 Javascript
JavaScript对象学习经验整理
Oct 12 Javascript
js中将String转换为number以便比较
Jul 08 Javascript
jQuery 1.9.1源码分析系列(十)事件系统之绑定事件
Nov 19 Javascript
AngularJS教程之MVC体系结构详解
Aug 16 Javascript
angularjs之$timeout指令详解
Jun 13 Javascript
基于JavaScript实现幸运抽奖页面
Jul 05 Javascript
如何解决js函数防抖、节流出现的问题
Jun 17 Javascript
vue-cli设置css不生效的解决方法
Feb 07 Javascript
微信小程序实现列表的横向滑动方式
Jul 15 Javascript
使用vue3重构拼图游戏的实现示例
Jan 25 Vue.js
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新手上路(九)
2006/10/09 PHP
php快递单号查询接口使用示例
2014/05/05 PHP
详解Yii2.0 rules验证规则集合
2017/03/21 PHP
ThinkPHP类似AOP思想的参数验证的实现方法
2019/12/18 PHP
php redis setnx分布式锁简单原理解析
2020/10/23 PHP
img标签中onerror用法
2009/08/13 Javascript
JavaScript 函数式编程的原理
2009/10/16 Javascript
jQuery jqgrid 对含特殊字符json 数据的 Java 处理方法
2011/01/01 Javascript
jQuery 选择表格(table)里的行和列及改变简单样式
2012/12/15 Javascript
js 获取、清空input type=&quot;file&quot;的值(示例代码)
2013/12/24 Javascript
javascript记录文本框内文字个数检测文字个数变化
2014/10/14 Javascript
js实现ArrayList功能附实例代码
2014/10/29 Javascript
node.js中的path.normalize方法使用说明
2014/12/08 Javascript
PageSwitch插件实现100种不同图片切换效果
2015/07/28 Javascript
AngularJS中实现显示或隐藏动画效果的方式总结
2015/12/31 Javascript
jQuery自定义滚动条完整实例
2016/01/08 Javascript
详解Angularjs 如何自定义Img的ng-load 事件
2017/02/15 Javascript
JavaScript正则表达式简单实用实例
2017/06/23 Javascript
如何理解Vue的.sync修饰符的使用
2017/08/17 Javascript
vue2实现可复用的轮播图carousel组件详解
2017/11/27 Javascript
浅谈HTTP 缓存的那些事儿
2018/10/17 Javascript
vue中tab选项卡的实现思路
2018/11/25 Javascript
layui 弹出层回调获取弹出层数据的例子
2019/09/02 Javascript
如何实现删除numpy.array中的行或列
2018/05/08 Python
python opencv判断图像是否为空的实例
2019/01/26 Python
利用python在大量数据文件下删除某一行的例子
2019/08/21 Python
基于python检查矩阵计算结果
2020/05/21 Python
python+django+selenium搭建简易自动化测试
2020/08/19 Python
HTML5实现移动端弹幕动画效果
2019/08/01 HTML / CSS
团日活动策划书
2014/02/01 职场文书
部门群众路线教育实践活动对照检查材料思想汇报
2014/10/07 职场文书
学校计划生育责任书
2015/05/09 职场文书
社区志愿者服务心得体会
2016/01/22 职场文书
《所见》教学反思
2016/02/23 职场文书
实现一个简单得数据响应系统
2021/11/11 Javascript
Flutter Navigator 实现路由传递参数
2022/04/22 Java/Android