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中的类继承
Nov 25 Javascript
javascript在myeclipse中报错的解决方法
Oct 29 Javascript
ExpressJS入门实例
Jan 14 Javascript
js实现图片和链接文字同步切换特效的方法
Feb 20 Javascript
在javaScript中检测数据类型的几种方式小结
Mar 04 Javascript
ES6入门教程之Class和Module详解
May 17 Javascript
Three.js基础学习教程
Nov 16 Javascript
详解vue移动端日期选择组件
Feb 22 Javascript
koa2 用户注册、登录校验与加盐加密的实现方法
Jul 22 Javascript
解决layer弹出层msg的文字不显示的问题
Sep 11 Javascript
Vue+elementUI实现多图片上传与回显功能(含回显后继续上传或删除)
Mar 23 Javascript
基于JavaScript实现随机点名器
Feb 25 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修改session_id示例代码
2014/01/08 PHP
smarty中js的调用方法示例
2014/10/27 PHP
PHP图片处理之使用imagecopyresampled函数实现图片缩放例子
2014/11/19 PHP
YII2框架中excel表格导出的方法详解
2017/07/21 PHP
解析DHTML,JavaScript,DOM,BOM以及WEB标准的描述
2013/06/19 Javascript
JS小游戏之象棋暗棋源码详解
2014/09/25 Javascript
JavaScript实现自动变换表格边框颜色
2015/05/08 Javascript
逻辑表达式中与或非的用法详解
2016/06/06 Javascript
从重置input file标签中看jQuery的 .val() 和 .attr(“value”) 区别
2016/06/12 Javascript
想学习javascript JS和jQuery哪个重要 先学哪个
2016/12/11 Javascript
js实现横向拖拽导航条功能
2017/02/17 Javascript
vue实现nav导航栏的方法
2017/12/13 Javascript
Angular5中提取公共组件之radio list的实例代码
2018/07/10 Javascript
vsCode安装使用教程和插件安装方法
2020/08/24 Javascript
使用 vue 实例更好的监听事件及vue实例的方法
2019/04/22 Javascript
JavaScript和TypeScript中的void的具体使用
2019/09/12 Javascript
layui使用表格渲染获取行数据的例子
2019/09/13 Javascript
jQuery实现鼠标放置名字上显示详细内容气泡提示框效果的方法分析
2020/04/04 jQuery
JavaScript运行机制实例分析
2020/04/11 Javascript
浅谈JS for循环中使用break和continue的区别
2020/07/21 Javascript
vue 页面回退mounted函数不执行的解决方案
2020/07/26 Javascript
OpenLayer3自定义测量控件MeasureTool
2020/09/28 Javascript
Python读写Json涉及到中文的处理方法
2016/09/12 Python
Python实现的桶排序算法示例
2017/11/29 Python
在python3中pyqt5和mayavi不兼容问题的解决方法
2019/01/08 Python
pycharm的console输入实现换行的方法
2019/01/16 Python
python使用Windows的wmic命令监控文件运行状况,如有异常发送邮件报警
2021/01/30 Python
IE8下CSS3选择器nth-child() 不兼容问题的解决方法
2016/11/16 HTML / CSS
大四毕业生学习总结的自我评价
2013/10/31 职场文书
应届生会计求职信
2013/11/11 职场文书
策划助理岗位职责
2013/11/18 职场文书
大学自主招生推荐信
2014/05/10 职场文书
公司开业的祝贺语大全(60条)
2019/07/05 职场文书
导游词之扬州大明寺
2019/10/09 职场文书
php 文件上传至OSS及删除远程阿里云OSS文件
2021/07/04 PHP
linux下安装redis图文详细步骤
2021/12/04 Redis