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 相关文章推荐
非常好用的JsonToString 方法 简单实例
Jul 18 Javascript
jQuery/CSS3图片特效插件整理推荐
Dec 07 Javascript
js实现最短的XML格式化工具实例
Mar 12 Javascript
bootstrap布局中input输入框右侧图标点击功能
May 16 Javascript
Node.js DES加密的简单实现
Jul 07 Javascript
Vue.js教程之计算属性
Nov 11 Javascript
VueAwesomeSwiper在VUE中的使用以及遇到的一些问题
Jan 11 Javascript
webpack4 入门最简单的例子介绍
Sep 05 Javascript
基于vue-cli、elementUI的Vue超简单入门小例子(推荐)
Apr 17 Javascript
vue自动化路由的实现代码
Sep 30 Javascript
js加减乘除精确运算方法实例代码
Jan 17 Javascript
Vue全家桶入门基础教程
May 14 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
《五等分的花嫁》漫画完结!2020年10月第2期TV动画制作组换血!
2020/03/06 日漫
Laravel 修改验证异常的响应格式实例代码详解
2020/05/25 PHP
JavaScript 数组详解
2013/10/10 Javascript
jquery实现的仿天猫侧导航tab切换效果
2015/08/24 Javascript
JQuery.Ajax()的data参数类型实例详解
2015/11/20 Javascript
Extjs4.0 ComboBox如何实现三级联动
2016/05/11 Javascript
Vue.js如何优雅的进行form validation
2017/04/07 Javascript
兼容浏览器的js事件绑定函数(详解)
2017/05/09 Javascript
详解Vue.js中.native修饰符
2018/04/24 Javascript
小程序数据通信方法大全(推荐)
2019/04/15 Javascript
elementui之el-tebs浏览器卡死的问题和使用报错未注册问题
2019/07/06 Javascript
Typescript的三种运行方式(小结)
2019/09/18 Javascript
JS实现简易计算器
2020/02/14 Javascript
JS字符串补全方法padStart()和padEnd()
2020/05/27 Javascript
微信小程序上传帖子的实例代码(含有文字图片的微信验证)
2020/07/11 Javascript
解决vue中axios设置超时(超过5分钟)没反应的问题
2020/09/04 Javascript
python回溯法实现数组全排列输出实例分析
2015/03/17 Python
PyMongo安装使用笔记
2015/04/27 Python
python 上下文管理器及自定义原理解析
2019/11/19 Python
Python破解BiliBili滑块验证码的思路详解(完美避开人机识别)
2020/02/17 Python
Pytorch数据拼接与拆分操作实现图解
2020/04/30 Python
Python3创建Django项目的几种方法(3种)
2020/06/03 Python
详解HTML5通讯录获取指定多个人的信息
2016/12/20 HTML / CSS
Lookfantastic瑞典:英国知名美妆购物网站
2018/04/06 全球购物
如何写出好的Java代码
2014/04/25 面试题
公司道歉信范文
2014/01/09 职场文书
公务员中国梦演讲稿
2014/08/19 职场文书
如何写股份合作协议书
2014/09/11 职场文书
大四优秀党员个人民主评议
2014/09/19 职场文书
医生个人自我剖析材料
2014/10/08 职场文书
幼儿教师师德师风自我评价
2015/03/05 职场文书
2015年实习班主任工作总结
2015/04/23 职场文书
会计实训总结范文
2015/08/03 职场文书
班主任工作总结范文
2015/08/13 职场文书
java实现面板之间切换功能
2022/06/10 Java/Android
MySQL主从切换的超详细步骤
2022/06/28 MySQL