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 相关文章推荐
Js获取事件对象代码
Aug 05 Javascript
Javascript的常规数组和关联数组对比小结
May 24 Javascript
变量声明时命名与变量作为对象属性时命名的区别解析
Dec 06 Javascript
javascript实现根据身份证号读取相关信息
Dec 17 Javascript
JavaScript包装对象使用详解
Jul 09 Javascript
基于javascript实现动态显示当前系统时间
Jan 28 Javascript
一道关于JavaScript变量作用域的面试题
Mar 08 Javascript
sso跨域写cookie的一段js脚本(推荐)
May 25 Javascript
JS防止网页被嵌入iframe框架的方法分析
Sep 13 Javascript
JS仿JQuery选择器功能
Mar 08 Javascript
Vue项目全局配置微信分享思路详解
May 04 Javascript
js贪心算法 钱币找零问题代码实例
Sep 11 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使用get_class_methods()函数获取分类的方法
2016/07/20 PHP
PHP中单例模式与工厂模式详解
2017/02/17 PHP
laravel-admin 实现在指定的相册下添加照片
2019/10/21 PHP
JavaScript是否可实现多线程  深入理解JavaScript定时机制
2009/12/22 Javascript
Highcharts 非常实用的Javascript统计图demo示例
2013/07/03 Javascript
判断ie的两种简单方法
2013/08/12 Javascript
JS:window.onload的使用介绍
2013/11/13 Javascript
js实现改进的仿蓝色论坛导航菜单效果代码
2015/09/06 Javascript
ES6记录异步函数的执行时间详解
2016/08/31 Javascript
jQuery编写textarea输入字数限制代码
2017/03/23 jQuery
angular2模块和共享模块详解
2018/04/08 Javascript
js简单遍历获取对象中的属性值的方法示例
2019/06/19 Javascript
解决LayUI数据表格复选框不居中显示的问题
2019/09/25 Javascript
[03:37]2016完美“圣”典 风云人物:Mikasa专访
2016/12/07 DOTA
[00:32]2018DOTA2亚洲邀请赛Newbee出场
2018/04/03 DOTA
[00:31]DOTA2荣耀之路7:Miracle-空血无敌斩
2018/05/31 DOTA
Python socket C/S结构的聊天室应用实现
2014/11/30 Python
Python错误: SyntaxError: Non-ASCII character解决办法
2017/06/08 Python
Python实现树的先序、中序、后序排序算法示例
2017/06/23 Python
python 提取tuple类型值中json格式的key值方法
2018/12/31 Python
浅析Python3中的对象垃圾收集机制
2019/06/06 Python
基于Python安装pyecharts所遇的问题及解决方法
2019/08/12 Python
修改 CentOS 6.x 上默认Python的方法
2019/09/06 Python
Python + Flask 实现简单的验证码系统
2019/10/01 Python
python实现贪吃蛇双人大战
2020/04/18 Python
Python中的整除和取模实例
2020/06/03 Python
Claire’s法国:时尚配饰、美容、珠宝、头发
2021/01/16 全球购物
戴尔荷兰官方网站:Dell荷兰
2020/10/04 全球购物
小型女装店的创业计划书
2014/01/09 职场文书
青蓝工程实施方案
2014/03/27 职场文书
松材线虫病防治方案
2014/06/15 职场文书
2015年春节标语口号
2014/12/09 职场文书
中标通知书格式
2015/04/17 职场文书
学习新党章心得体会2016
2016/01/15 职场文书
SONY AN-LP1 短波有源天线放大器
2021/04/22 无线电
微信小程序结合ThinkPHP5授权登陆后获取手机号
2021/11/23 PHP