【vue-router】当router-link被点击后都发生了什么

90 阅读1分钟
  1. router-link组件 通过render函数来定义组件的输出,绕过了模版编译的过程。在render函数中定义了router-link被点击触发的事件handler,通过createElement函数渲染dom。
// 当组件的options有render时,就不进行模板编译compileToFunctions生成render渲染函数
// 直接通过你组件定义的options的render生成虚拟dom。
render (h: Function) {
   // 点击触发的函数
   const handler = e => {
      if (guardEvent(e)) {
        if (this.replace) {
          router.replace(location, noop)
        } else {
          router.push(location, noop)
        }
      }
  }
  // 默认为a标签
  if (this.tag === 'a') {
      data.on = on
      data.attrs = { href, 'aria-current': ariaCurrentValue }
  } 
   // createElement函数渲染dom
   return h(this.tag, data, this.$slots.default)
}
  1. 当router-link被点击后,会触发handler。去执行当前mode(history、hash)的history的push
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
    const { current: fromRoute } = this
    this.transitionTo(location, route => {
      pushState(cleanPath(this.base + route.fullPath))
      handleScroll(this.router, route, fromRoute, false)
      onComplete && onComplete(route)
    }, onAbort)
}
  
transitionTo (
    location: RawLocation,
    onComplete?: Function,
    onAbort?: Function
  ) {
    let route
    // catch redirect option https://github.com/vuejs/vue-router/issues/3201
    try {
      route = this.router.match(location, this.current)
    } catch (e) {
      this.errorCbs.forEach(cb => {
        cb(e)
      })
      // Exception should still be thrown
      throw e
    }
    const prev = this.current
    this.confirmTransition(
      route,
      () => {
        // 设置响应式数据触发router-view视图更新
        this.updateRoute(route)
        onComplete && onComplete(route)
        this.ensureURL()
        this.router.afterHooks.forEach(hook => {
          hook && hook(route, prev)
        })

        // 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) {
          if (!isNavigationFailure(err, NavigationFailureType.redirected) || prev !== START) {
            this.ready = true
            this.readyErrorCbs.forEach(cb => {
              cb(err)
            })
          }
        }
      }
    )
  }

3.在transitionTo方法中执行this.updateRoute(route), cb函数设置vue实例上响应式_router的值,触发router-view的组件视图更新

updateRoute (route: Route) {
    this.current = route
    this.cb && this.cb(route)
}
// this.cb
this.apps.forEach(app => {
        app._route = route
})