zoukankan      html  css  js  c++  java
  • vue-router源码随笔2

    执行完Vue实例的beforeCreate钩子函数之后,接下解析<router-Link>和<router-view>这两个组件,并渲染到页面中。执行组件的render方法,

    // 可以忽略,只需要知道是把to(目标组件)路径格式化,
    // route 为location匹配到在Router中的路由对象,
    // href为route完整的链接。这里涉及到很多比较难看的函数,要抽象出来,不要绕进去。
    const { location, route, href } = router.resolve(
       this.to,
       current,
       this.append
     )

     整个render都是在围绕构造虚拟Dom的data对象。其中对slot和tag进行了处理,总的来说,可以先忽略细节,认识到作用。<router-view>是个函数组件(也就是说它只是展示,没有数据监听,

    没有this,没有钩子函数,它的render函数的第二个参数为render函数执行的上下文),router-view渲染之前注册了三个钩子函数:registerRouteInstance(组件初始beforeCreate执行)、

    prepatch、init,这些钩子函数会在组件patch阶段按顺序一一执行,最终渲染当前route的组件。通过上面的解析,重点在于:
    const route = parent.$route    //route是怎么变化的,这个变化会导致页面重新渲染。
    const matched = route.matched[depth]

     $route变化在每个History实例中的调用transitionTo引起的,

    /* app 为 Vue实例*/
    history.listen(route => {
          this.apps.forEach((app) => {
            app._route = route
          })
    })
    // 把listen赋值给History的回调函数,history具有回调函数。
    listen (cb: Function) {
       this.cb = cb
    }
    // 这个cb在update钩子函数中执行
    updateRoute (route: Route) {
        this.current = route
        this.cb && this.cb(route)
    }
    // _router的变化导致页面更新
    Vue.util.defineReactive(this, '_route', this._router.history.current)

    而updateRouter在confirmTransition()中执行,confirmTransition又是transitionTo里执行。confirmTransition是vue-router难点,它涉及到导航的守护钩子函数。

    导航守护钩子函数:对照官方文档按照顺序对照源码比较好。

    // deactivated为失活组件,updated需要更新的组件,activated激活的组件
    const { updated, deactivated, activated } = resolveQueue(
        this.current.matched,
        route.matched
     )
    const queue: Array<?NavigationGuard> = [].concat(
          // in-component leave guards
          // 执行beforeRouterLeave守卫
          extractLeaveGuards(deactivated),
          // global before hooks // 全局配置守卫
          this.router.beforeHooks,
          // in-component update hooks
          // beforeRouteUpdate守卫
          extractUpdateHooks(updated),
          // 在路由配置里调用 beforeEnter
          activated.map(m => m.beforeEnter),
          // async components
          //解析异步路由组件
          resolveAsyncComponents(activated)
        )

    extractLeaveGuards(deactivated) 返回函数数组。

    function bindGuard (guard: NavigationGuard, instance: ?_Vue): ?NavigationGuard {
      // instance为闭包变量,也就是说赋值的那个数组函数中,instance会一直存在
      if (instance) {
        return function boundRouteGuard () {
          return guard.apply(instance, arguments)  // 在组件实例执行钩子函数
        }
      }
    }
    function extractLeaveGuards (deactivated: Array<RouteRecord>): Array<?Function> {
      //bindGuard 为函数闭包
      return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
    }

    比较难看,要坚持下去,看看 extractLeaveGuards的数组是怎么形成的,extractGuards:

    function extractGuard (
      def: Object | Function,
      key: string
    ): NavigationGuard | Array<NavigationGuard> {
      if (typeof def !== 'function') {
        // extend now so that global mixins are applied.
        def = _Vue.extend(def)  //组件继承Vue 
      }
      return def.options[key]   // 获取组件的钩子函数
    }
    function extractGuards (
      records: Array<RouteRecord>,
      name: string,
      bind: Function,
      reverse?: boolean
    ): Array<?Function> {
      // 参数是目前的router数组,和一个回调,
      const guards = flatMapComponents(records, (def, instance, match, key) => {
        const guard = extractGuard(def, name)
        if (guard) {
          return Array.isArray(guard)
            ? guard.map(guard => bind(guard, instance, match, key))
            : bind(guard, instance, match, key) // 返回执行钩子的方法。
        }
      })
      //guards 就是我们想要的函数数组,它是个一维数组。
      return flatten(reverse ? guards.reverse() : guards)
    }
    // flatMapComponents定义如下:
    export function flatMapComponents (
      matched: Array<RouteRecord>,
      fn: Function
    ): Array<?Function> {
      // 对matched中每个成员的components中的每个组件用回调函数处理。
      return flatten(matched.map(m => {
        return Object.keys(m.components).map(key => fn(
          m.components[key],
          m.instances[key],
          m, key
        ))
      }))
    }

     看完extractLeaveGuards,执行全局beforeHooks钩子函数,接着执行extractUpdateHooks函数,这函数和extractLeaveGuards类似。只是name为“beforeRouteUpdate”,接着是每个activated组件执行beforeEnter钩子函数,处理activated异步组件。

  • 相关阅读:
    thinkphp在模型中自动完成session赋值
    highcharts实例教程二:结合php与mysql生成饼图
    程序员应该经常看看的网站
    highcharts实例教程一:结合php与mysql生成折线图
    2015-2-10 ecshop
    一个简单的javascript获取URL参数的代码
    table 西边框样式
    PHP 获取当前日期及格式化
    mysql 获取当前日期及格式化
    mysql时间int日期转换
  • 原文地址:https://www.cnblogs.com/liuyinlei/p/13126225.html
Copyright © 2011-2022 走看看