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实现图片的前进与后退功能
Apr 24 Javascript
解析window.open的使用方法总结
Jun 19 Javascript
禁止拷贝网页内容的js代码
Jan 22 Javascript
jquery使用ajax实现微信自动回复插件
Apr 28 Javascript
js实现iGoogleDivDrag模块拖动层拖动特效的方法
Mar 04 Javascript
Javascript中的call()方法介绍
Mar 15 Javascript
基于javascript制作经典传统的拼图游戏
Mar 22 Javascript
Javascript iframe交互并兼容各种浏览器的解决方法
Jul 12 Javascript
关于javascript的一些知识以及循环详解
Sep 12 Javascript
微信小程序 五星评分(包括半颗星评分)实例代码
Dec 14 Javascript
js实现数字从零慢慢增加到指定数字示例
Nov 07 Javascript
如何用JavaScipt测网速
May 09 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 判断访客是否为搜索引擎蜘蛛的函数代码
2011/07/29 PHP
php简单图像创建入门实例
2015/06/10 PHP
如何批量清理系统临时文件(语言:C#、 C/C++、 php 、python 、java )
2016/02/01 PHP
PHP连接MSSQL方法汇总
2016/02/05 PHP
PHP pthreads v3下同步处理synchronized用法示例
2020/02/21 PHP
js 表单验证方法(实用)
2009/04/28 Javascript
jquery 应用代码 方便的排序功能
2010/02/06 Javascript
使用jQuery的easydrag插件实现可拖动的DIV弹出框
2016/02/19 Javascript
JS面向对象(3)之Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法
2016/02/25 Javascript
使用RequireJS库加载JavaScript模块的实例教程
2016/06/06 Javascript
webpack多页面开发实践
2017/12/18 Javascript
JS中使用textPath实现线条上的文字
2017/12/25 Javascript
用Axios Element实现全局的请求loading的方法
2018/03/15 Javascript
详解Vue中数组和对象更改后视图不刷新的问题
2018/09/21 Javascript
js、jquery实现列表模糊搜索功能过程解析
2020/03/27 jQuery
解决VUE 在IE下出现ReferenceError: Promise未定义的问题
2020/11/07 Javascript
在Linux系统上部署Apache+Python+Django+MySQL环境
2015/12/24 Python
python ipset管理 增删白名单的方法
2019/01/14 Python
PyTorch 随机数生成占用 CPU 过高的解决方法
2020/01/13 Python
Python虚拟环境库virtualenvwrapper安装及使用
2020/06/17 Python
Flask中sqlalchemy模块的实例用法
2020/08/02 Python
python爬虫多次请求超时的几种重试方法(6种)
2020/12/01 Python
使用html5 canvas绘制圆环动效
2019/06/03 HTML / CSS
有趣的流行文化T恤、马克杯、手机壳和更多:Look Human
2019/01/07 全球购物
购买正版游戏和游戏激活码:Green Man Gaming
2019/11/06 全球购物
Linux不知道文件后缀名怎么判断文件类型
2014/08/21 面试题
AJax面试题
2014/11/25 面试题
临床医学应届生求职信
2013/11/06 职场文书
工业自动化专业毕业生推荐信
2013/11/18 职场文书
成功经营餐厅的创业计划书范文
2013/12/26 职场文书
校园创业策划书
2014/01/14 职场文书
材料会计岗位职责
2014/03/06 职场文书
教师岗位聘任书范文
2014/03/29 职场文书
2014年信访维稳工作总结
2014/12/08 职场文书
JavaScript前端面试扁平数据转tree与tree数据扁平化
2022/06/14 Javascript
LyScript实现绕过反调试保护的示例详解
2022/08/14 Python