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实现广告漂浮效果的小例子
Jul 02 Javascript
分享Javascript中最常用的55个经典小技巧
Nov 29 Javascript
ie9 提示'console' 未定义问题的解决方法
Mar 20 Javascript
图片放大镜jquery.jqzoom.js使用实例附放大镜图标
Jun 19 Javascript
JavaScript跨域调用基于JSON的RESTful API
Jul 09 Javascript
原生js的RSA和AES加密解密算法
Oct 08 Javascript
angular实现商品筛选功能
Feb 01 Javascript
使用原生js封装的ajax实例(兼容jsonp)
Oct 12 Javascript
Vue.js实现双向数据绑定方法(表单自动赋值、表单自动取值)
Aug 27 Javascript
vue里input根据value改变背景色的实例
Sep 29 Javascript
关于vue组件事件属性穿透详解
Oct 28 Javascript
微信h5静默和非静默授权获取用户openId的方法和步骤
Jun 08 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 表单提交给自己
2008/07/24 PHP
elgg 获取文件图标地址的方法
2010/03/20 PHP
php array_filter除去数组中的空字符元素
2020/06/21 PHP
基于PHP生成简单的验证码
2016/06/01 PHP
JS 文字符串转换unicode编码函数
2009/05/30 Javascript
jquery mobile changepage的三种传参方法介绍
2013/09/13 Javascript
JS实现DIV容器赋值的方法
2015/12/14 Javascript
全面解析Bootstrap中tab(选项卡)的使用方法
2016/06/06 Javascript
js中删除数组中的某一元素实例(无下标时)
2017/02/28 Javascript
windows下vue.js开发环境搭建教程
2017/03/20 Javascript
Three.js实现绘制字体模型示例代码
2017/09/26 Javascript
vue组件父子间通信详解(三)
2017/11/07 Javascript
浅谈Vue 数据响应式原理
2018/05/07 Javascript
vue动态路由配置及路由传参的方式
2018/05/23 Javascript
详解Angular6.0使用路由步骤(共7步)
2018/06/29 Javascript
使用layui 渲染table数据表格的实例代码
2018/08/19 Javascript
Javascript迭代、递推、穷举、递归常用算法实例讲解
2019/02/01 Javascript
JS如何生成随机验证码
2020/03/02 Javascript
JavaScript实现拖拽效果
2020/03/16 Javascript
[04:52]第二届DOTA2亚洲邀请赛主赛事第一天比赛集锦:OG娜迦海妖放大配合谜团大中3人
2017/04/02 DOTA
[03:11]不朽宝藏三外观展示
2020/09/18 DOTA
Python学习笔记(一)(基础入门之环境搭建)
2014/06/05 Python
python 列表删除所有指定元素的方法
2018/04/19 Python
Python自动化完成tb喵币任务的操作方法
2019/10/30 Python
python将图片转base64,实现前端显示
2020/01/09 Python
Python3 socket即时通讯脚本实现代码实例(threading多线程)
2020/06/01 Python
Python flask路由间传递变量实例详解
2020/06/03 Python
CSS Grid布局教程之什么是网格布局
2014/12/30 HTML / CSS
应届生保险求职信
2013/11/11 职场文书
学校安全检查制度
2014/01/27 职场文书
校园摄影活动策划方案
2014/02/05 职场文书
德育标兵事迹材料
2014/08/24 职场文书
工作疏忽检讨书500字
2014/10/26 职场文书
雷峰塔导游词
2015/02/09 职场文书
2016元旦晚会主持词开场白和结束语
2015/12/04 职场文书
用 Python 定义 Schema 并生成 Parquet 文件详情
2021/09/25 Python