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继承 Base类的源码解析
Dec 30 Javascript
Mootools 1.2教程 同时进行多个形变动画
Sep 15 Javascript
jQuery技巧总结
Jan 01 Javascript
结合代码图文讲解JavaScript中的作用域与作用域链
Jul 05 Javascript
详解从新建vue项目到引入组件Element的方法
Aug 29 Javascript
vue2.0.js的多级联动选择器实现方法
Feb 09 Javascript
浅谈vue项目如何打包扔向服务器
May 08 Javascript
简单明了区分escape、encodeURI和encodeURIComponent
May 26 Javascript
bootstrap table合并行数据并居中对齐效果
Oct 17 Javascript
ElementUI 修改默认样式的几种办法(小结)
Jul 29 Javascript
vue+Element-ui实现登录注册表单
Nov 17 Javascript
详解JSON.parse和JSON.stringify用法
Feb 18 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
【动漫杂谈】关于《请在T台上微笑》
2020/03/03 日漫
PHP+Mysql+jQuery实现动态展示信息
2011/10/08 PHP
phpMyAdmin无法登陆的解决方法
2017/04/27 PHP
php 调用百度sms来发送短信的实现示例
2018/11/02 PHP
JavaScript 高效运行代码分析
2010/03/18 Javascript
jquery 模拟雅虎首页的点击对话框效果
2010/04/11 Javascript
JavaScript日历实现代码
2010/09/12 Javascript
基于JQuery的访问WebService的代码(可访问Java[Xfire])
2010/11/19 Javascript
JSDoc 介绍使用规范JsDoc的使用介绍
2011/02/12 Javascript
15款优秀的jQuery导航菜单插件分享
2011/07/19 Javascript
深入理解JavaScript系列(3) 全面解析Module模式
2012/01/15 Javascript
Nodejs极简入门教程(三):进程
2014/10/27 NodeJs
JavaScript中的splice()方法使用详解
2015/06/09 Javascript
angular-ui-sortable实现可拖拽排序列表
2016/12/28 Javascript
基于JavaScript实现熔岩灯效果导航菜单
2017/01/04 Javascript
JavaScript中清空数组的三种方式
2017/03/22 Javascript
vue中如何使用ztree
2018/02/06 Javascript
使用Vue.js和Element-UI做一个简单登录页面的实例
2018/02/23 Javascript
vue实现键盘输入支付密码功能
2018/08/18 Javascript
解决 viewer.js 动态更新图片导致无法预览的问题
2019/05/14 Javascript
JS实现简单省市二级联动
2019/11/27 Javascript
JavaScript oncopy事件用法实例解析
2020/05/13 Javascript
JavaScript位置参数实现原理及过程解析
2020/09/14 Javascript
在Python的Django框架中创建和使用模版
2015/07/15 Python
Windows下的Python 3.6.1的下载与安装图文详解(适合32位和64位)
2018/02/21 Python
Python3标准库之threading进程中管理并发操作方法
2020/03/30 Python
python 实现一个图形界面的汇率计算器
2020/11/09 Python
服务中心夜班服务员岗位职责
2013/11/27 职场文书
技校生自我鉴定
2013/12/08 职场文书
学校万圣节活动方案
2014/02/13 职场文书
大学生职业生涯规划书汇总
2014/03/20 职场文书
广告艺术设计专业自荐书
2014/07/08 职场文书
入党积极分子学习优秀共产党员先进事迹思想汇报
2014/09/13 职场文书
银行求职自荐信范文
2015/03/04 职场文书
复兴之路展览观后感
2015/06/02 职场文书
Java常用工具类汇总 附示例代码
2021/06/26 Java/Android