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中的eval函数
Nov 02 Javascript
JS中产生标识符方式的演变
Jun 12 Javascript
js实现大转盘抽奖游戏实例
Jun 24 Javascript
jQuery中ajax的load()与post()方法实例详解
Jan 05 Javascript
详解Vue2 SSR 缓存 Api 数据
Nov 20 Javascript
使用Vue组件实现一个简单弹窗效果
Apr 23 Javascript
jquery ui 实现 tab标签功能示例【测试可用】
Jul 25 jQuery
Flutter 超实用简单菜单弹出框 PopupMenuButton功能
Aug 06 Javascript
d3.js实现图形拖拽
Dec 19 Javascript
小程序新版订阅消息模板消息
Dec 31 Javascript
如何通过JS实现转码与解码
Feb 21 Javascript
JavaScript组合继承详解
Nov 07 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
DOTA2 1月28日更新:监管系统降临刀塔世界
2021/01/28 DOTA
PHP 手机归属地查询 api
2010/02/08 PHP
PHP版本常用的排序算法汇总
2015/12/20 PHP
PHP使用redis消息队列发布微博的方法示例
2017/06/22 PHP
php 删除一维数组中某一个值元素的操作方法
2018/02/01 PHP
javascript 学习之旅 (2)
2009/02/05 Javascript
js弹窗代码 可以指定弹出间隔
2010/07/03 Javascript
jquery中:input和input的区别分析
2011/07/13 Javascript
使用jQuery同时控制四张图片的伸缩实现代码
2013/04/19 Javascript
JS实现跟随鼠标立体翻转图片的方法
2015/05/04 Javascript
使用jquery实现鼠标滑过弹出更多相关信息层附源码下载
2015/11/23 Javascript
js实现楼层效果的简单实例
2016/07/15 Javascript
原生JS封装animate运动框架的实例
2017/10/12 Javascript
JavaScript编程设计模式之构造器模式实例分析
2017/10/25 Javascript
jQuery+SpringMVC中的复选框选择与传值实例
2018/01/08 jQuery
vue better-scroll插件使用详解
2018/01/25 Javascript
AngularJS实时获取并显示密码的方法
2018/02/06 Javascript
微信小程序项目总结之点赞 删除列表 分享功能
2018/06/25 Javascript
tornado 多进程模式解析
2018/01/15 Python
浅谈使用Python内置函数getattr实现分发模式
2018/01/22 Python
Python学习笔记之错误和异常及访问错误消息详解
2019/08/08 Python
python或C++读取指定文件夹下的所有图片
2019/08/31 Python
Django 实现外键去除自动添加的后缀‘_id’
2019/11/15 Python
python学生信息管理系统实现代码
2019/12/17 Python
python实现简单颜色识别程序
2020/02/19 Python
如何用Matlab和Python读取Netcdf文件
2021/02/19 Python
python 制作本地应用搜索工具
2021/02/27 Python
GEOX鞋美国官方网站:意大利会呼吸的鞋
2017/07/12 全球购物
说一下mysql, oracle等常见数据库的分页实现方案
2012/09/29 面试题
css animation配合SVG制作能量流动效果
2021/03/24 HTML / CSS
个人反四风对照检查材料思想汇报
2014/09/23 职场文书
国防教育标语
2014/10/08 职场文书
2014年发展党员工作总结
2014/11/12 职场文书
生日答谢词
2015/01/05 职场文书
鲁迅故里导游词
2015/02/05 职场文书
Go Grpc Gateway兼容HTTP协议文档自动生成网关
2022/06/16 Golang