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 相关文章推荐
Web跨浏览器进程通信(Web跨域)
Apr 17 Javascript
淘宝网提供的国内NPM镜像简介和使用方法
Apr 17 Javascript
详解addEventListener的三个参数之useCapture
Mar 16 Javascript
使用jQuery在对象中缓存选择器的简单方法
Jun 30 Javascript
js实现图片缓慢放大缩小效果
Aug 02 Javascript
如何在AngularJs中调用第三方插件库
May 21 Javascript
基于原生js运动方式关键点的总结(推荐)
Oct 01 Javascript
vue组件编写之todolist组件实例详解
Jan 22 Javascript
详解Vue2.0组件的继承与扩展
Nov 23 Javascript
详解VUE Element-UI多级菜单动态渲染的组件
Apr 25 Javascript
jQuery属性选择器用法实例分析
Jun 28 jQuery
Vue Render函数创建DOM节点代码实例
Jul 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
Smarty变量调节器失效的解决办法
2014/08/20 PHP
PHP中exec函数和shell_exec函数的区别
2014/08/20 PHP
如何解决PHP无法实现多线程的问题
2015/09/25 PHP
PHP数组实例详解
2016/06/26 PHP
php usort 使用用户自定义的比较函数对二维数组中的值进行排序
2017/05/02 PHP
PHP实现求两个字符串最长公共子串的方法示例
2017/11/17 PHP
laravel实现一个上传图片的接口,并建立软链接,访问图片的方法
2019/10/12 PHP
jquery pagination插件实现无刷新分页代码
2009/10/13 Javascript
用JQUERY增删元素的代码
2012/02/14 Javascript
JQuery防止退格键网页后退的实现代码
2012/03/23 Javascript
Extjs 4.x 得到form CheckBox 复选框的值
2014/05/04 Javascript
JavaScript字符串对象substring方法入门实例(用于截取字符串)
2014/10/17 Javascript
JavaScript实现可拖拽的拖动层Div实例
2015/08/05 Javascript
js模仿java的Map集合详解
2016/01/06 Javascript
jQuery实现对无序列表的排序功能(附demo源码下载)
2016/06/25 Javascript
详解nodejs 文本操作模块-fs模块(一)
2016/12/22 NodeJs
Angular的模块化(代码分享)
2016/12/26 Javascript
vue.js获取数据库数据实例代码
2017/05/26 Javascript
vue 基于element-ui 分页组件封装的实例代码
2018/12/10 Javascript
js核心基础之闭包的应用实例分析
2019/05/11 Javascript
使用webpack搭建vue项目及注意事项
2019/06/10 Javascript
vuex 实现getter值赋值给vue组件里的data示例
2019/11/05 Javascript
使用Vue 自定义文件选择器组件的实例代码
2020/03/04 Javascript
Python调用C++程序的方法详解
2017/01/24 Python
使用Python快速搭建HTTP服务和文件共享服务的实例讲解
2018/06/04 Python
numpy 对矩阵中Nan的处理:采用平均值的方法
2018/10/30 Python
python GUI库图形界面开发之PyQt5选项卡控件QTabWidget详细使用方法与实例
2020/03/01 Python
python中操作文件的模块的方法总结
2021/02/04 Python
CSS3 实现穿梭星空动画
2020/11/13 HTML / CSS
三严三实学习心得体会
2014/10/13 职场文书
合法的离婚协议书范本
2014/10/23 职场文书
销售会议开幕词
2015/01/28 职场文书
2015新学期家长寄语
2015/02/26 职场文书
因个人工作失误检讨书
2019/06/21 职场文书
Nginx+Tomcat实现负载均衡、动静分离的原理解析
2021/03/31 Servers
解决jupyter notebook启动后没有token的坑
2021/04/24 Python