vue-router之history类浅析

2019-05-21 admin

当前版本: 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() })
                    })
                }
            })
        })
    }

结语:

每一次总结,都是对之前读源码的再一次深入的了解

[转载]原文链接:https://segmentfault.com/a/1190000019238946

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-65411.html

文章标题:vue-router之history类浅析

相关文章
vue.js实现请求数据的方法示例
vue2.0示例代码如下: var vm = new Vue({ el:&quot;#list&quot;, data:{ gridData: &quot;&quot;, }, ...
2017-03-20
jQuery中DOM树操作之复制元素的方法
本文实例讲述了jQuery中DOM树操作之复制元素的方法。分享给大家供大家参考。具体分析如下: 复制元素 前面提到的操作包括:插人新创建的元素、将元素从文档中的一个位置移动 到另一个位置,以及通过新元素来包装已有的元素。可是,有时候也会用到...
2015-11-13
从 JavaScript 到 TypeScript - 声明类型
从 JavaScript 语法改写为 TypeScript 语法,有两个关键点,一点是类成员变量 (Field) 需要声明,另一点是要为各种东西 (变量、参数、函数 / 方法等) 声明类型。而这两个点直接引出了两个关键性的问题,有哪些类型?...
2017-06-05
Node.js的不足之处
跨平台编程能力不够强大 Bowery团队指出Go能很方便地在不同系统里进行程序编译,这是他们转入Go的重要原因之一。 作为开发平台,对Linux,Windows,OSX等常见操作系统提供支援是能否吸引开发者的基本要素。在Go中,开发者可以针...
2015-11-12
三步搞定vue在vscode的环境配置问题
1. vscode基础开发插件 vscode-icons 图标美化 Debugger for Chrome 调试 Beautify 代码格式化 Prettier 代码格式化 ESLint 代码规范 JavaScript (ES6) cod...
2017-12-25
vuejs通过filterBy、orderBy实现搜索筛选、降序排序数据
直接贴代码了: 先上输入前的样子: &lt;style&gt; #example{margin:100px auto;width:600px;} .show{margin:10px;} #searchText{display: block...
2017-03-17
vue-awesome-swiper的使用以及API整理
一、先说一个看关于vue-awesome-swiper的一个坑 vue项目的package.json中显示的&lt;span style=“color: orange;”&gt;“vue-awesome-swiper”: “^2.5.4”&...
2018-04-26
最细致的vue.js基础语法 值得收藏!
介绍 前段时间接触到一个库叫做Vue.js, 个人感觉很棒,所以整理了一篇博文做个介绍。 Vue读音/vju:/,和view类似。是一个数据驱动的web界面库。Vue.js只聚焦于视图层,可以很容易的和其他库整合。代码压缩后只有24kb。 ...
2017-03-21
JS中Select下拉列表类(支持输入模糊查询)功能
下面给大家分享一段代码关于select下拉列表类支持输入模糊查询功能的实现代码,具体代码如下所示: &lt;span style=&quot;font-size:14px;&quot;&gt; &lt;HTML&gt; &lt...
2017-03-06
mpvue 小程序如何开启下拉刷新,上拉加载?
https://developers.weixin.qq.com/miniprogram/dev/api/pulldown.html#onpulldownrefresh 小程序API 微信小程序之下拉加载和上拉刷新 微信小程序下拉加载和上拉...
2018-05-25
回到顶部