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 相关文章推荐
Windows Live的@live.com域名注册漏洞 利用代码
Dec 27 Javascript
js onkeypress与onkeydown 事件区别详细说明
Dec 13 Javascript
通过jQuery源码学习javascript(二)
Dec 27 Javascript
js this函数调用无需再次抓获id,name或标签名
Mar 03 Javascript
javascript常用方法总结
May 14 Javascript
javascript运算符——位运算符全面介绍
Jul 14 Javascript
最原始的jQuery注册验证方式
Oct 11 Javascript
详解Vue中状态管理Vuex
May 11 Javascript
在vue-cli搭建的项目中增加后台mock接口的方法
Apr 26 Javascript
微信小程序实现笑脸评分功能
Nov 03 Javascript
Vue路由前后端设计总结
Aug 06 Javascript
vue+vant 上传图片需要注意的地方
Jan 03 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
叶罗丽:为什么大家对颜冰这对CP非常关心,却对金茉两人十分冷漠
2020/03/17 国漫
php站内搜索并高亮显示关键字的实现代码
2011/12/29 PHP
PHP使用GIFEncoder类生成gif动态滚动字幕
2014/07/01 PHP
php命令行用法入门实例教程
2014/10/27 PHP
php生成短域名函数
2015/03/23 PHP
php中的依赖注入实例详解
2019/08/14 PHP
laravel5.6 框架操作数据 Eloquent ORM用法示例
2020/01/26 PHP
php判断数组是否为空的实例方法
2020/05/10 PHP
Laravel Reponse响应客户端示例详解
2020/09/03 PHP
jquery实现的让超出显示范围外的导航自动固定屏幕最顶上
2011/09/22 Javascript
裁剪字符串trim()自定义改进版
2013/04/10 Javascript
JS中引用百度地图并将百度地图的logo和信息去掉
2013/09/29 Javascript
深入理解JavaScript系列(47):对象创建模式(上篇)
2015/03/04 Javascript
jQuery实现固定在网页顶部的菜单效果代码
2015/09/02 Javascript
jQuery常用知识点总结以及平时封装常用函数
2016/02/23 Javascript
获取input标签的所有属性的方法
2016/06/28 Javascript
jQuery中常用动画效果函数(日常整理)
2016/09/17 Javascript
JS实现字符串转驼峰格式的方法
2016/12/16 Javascript
AngularJS实现的回到顶部指令功能实例
2017/05/17 Javascript
angular+webpack2实战例子
2017/05/23 Javascript
JavaScript函数中的this四种绑定形式
2017/08/15 Javascript
vue 组件中添加样式不生效的解决方法
2018/07/06 Javascript
jQuery+ajax实现批量删除功能完整示例
2019/06/06 jQuery
Vue动态创建注册component的实例代码
2019/06/14 Javascript
使用vue3重构拼图游戏的实现示例
2021/01/25 Vue.js
[02:40]DOTA2英雄基础教程 巨牙海民
2013/12/23 DOTA
python爬虫_自动获取seebug的poc实例
2017/08/05 Python
python 实现简单的FTP程序
2019/12/27 Python
opencv 形态学变换(开运算,闭运算,梯度运算)
2020/07/07 Python
新加坡时尚网上购物:Zalora新加坡
2016/07/26 全球购物
机械工程师求职自我评价
2013/09/23 职场文书
教师通用专业自荐书范文
2014/02/11 职场文书
小学生纪律委员竞选稿
2015/11/19 职场文书
幼儿园托班开学寄语(2016秋季)
2015/12/03 职场文书
《秋天的怀念》教学反思
2016/02/17 职场文书
漫画「古见同学有交流障碍症」第25卷封面公开
2022/03/21 日漫