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 数值型和字符串型之间的转换
Jul 25 Javascript
通过jquery-ui中的sortable来实现拖拽排序的简单实例
May 24 Javascript
Servlet实现文件上传,可多文件上传示例
Dec 05 Javascript
如何提高数据访问速度
Dec 26 Javascript
bootstrapValidator表单验证插件学习
Dec 30 Javascript
Vim快速合并行及vim 将文件所有行合并到一行
Nov 27 Javascript
jQuery插件Validation表单验证详解
May 26 jQuery
angularjs结合html5实现拖拽功能
Jun 25 Javascript
postman自定义函数实现 时间函数的思路详解
Apr 17 Javascript
Bootstrap 时间日历插件bootstrap-datetimepicker配置与应用小结
May 28 Javascript
JS动态图片的实现方法完整示例
Jan 13 Javascript
Vue项目中使用mock.js的完整步骤
Jan 12 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
php发送html格式文本邮件的方法
2015/06/10 PHP
javascript全局变量封装模块实现代码
2012/11/28 Javascript
在页面中js获取光标/鼠标的坐标及光标的像素坐标
2013/11/11 Javascript
js鼠标点击图片切换效果代码分享
2015/08/26 Javascript
JS实现的仿QQ空间图片弹出效果代码
2016/02/23 Javascript
一次$.getJSON不执行的简单记录
2016/07/19 Javascript
jQuery+Pdo编写login登陆界面
2016/08/01 Javascript
前端js弹出框组件使用方法
2020/08/24 Javascript
使用JavaScript判断用户输入的是否为正整数(两种方法)
2017/02/05 Javascript
nodejs操作mongodb的填删改查模块的制作及引入实例
2018/01/02 NodeJs
ajax请求+vue.js渲染+页面加载的示例
2018/02/11 Javascript
微信小程序上传图片到php服务器的方法
2019/05/23 Javascript
js实现跳一跳小游戏
2020/07/31 Javascript
[01:10]DOTA2英雄背景故事第四期之混沌法则混沌骑士
2020/07/16 DOTA
K-means聚类算法介绍与利用python实现的代码示例
2017/11/13 Python
pip安装Python库时遇到的问题及解决方法
2017/11/23 Python
pygame实现简易飞机大战
2018/09/11 Python
python使用Pandas库提升项目的运行速度过程详解
2019/07/12 Python
python cumsum函数的具体使用
2019/07/29 Python
Python常用模块os.path之文件及路径操作方法
2019/12/03 Python
详解用Python爬虫获取百度企业信用中企业基本信息
2020/07/02 Python
html5实现的便签特效(实战分享)
2013/11/29 HTML / CSS
Rockport乐步美国官网:风靡美国的白宫鞋
2016/11/24 全球购物
阿根廷票务网站:StubHub阿根廷
2018/04/13 全球购物
软件设计的目标是什么
2016/12/04 面试题
青春演讲稿范文
2014/05/08 职场文书
地方白酒代理协议书
2014/10/25 职场文书
思想道德自我评价2015
2015/03/09 职场文书
学习型家庭事迹材料(2016精选版)
2016/02/29 职场文书
餐厅营销的秘密:为什么老顾客会流水?
2019/08/08 职场文书
比较node.js和Deno
2021/04/27 Javascript
教你使用Python pypinyin库实现汉字转拼音
2021/05/27 Python
详解Redis基本命令与使用场景
2021/06/01 Redis
解决Mysql多行子查询的使用及空值问题
2022/01/22 MySQL
pandas时间序列之pd.to_datetime()的实现
2022/06/16 Python
JavaScript架构搭建前端监控如何采集异常数据
2022/06/25 Javascript