首页 > 其他分享 >vue-router钩子执行顺序

vue-router钩子执行顺序

时间:2023-07-27 18:15:25浏览次数:54  
标签:vue return 钩子 guards failure push router beforeEnter

Vue的路由在执行跳转时,根据源码可知,调用了router中定义的navigate函数

function push(to: RouteLocationRaw) {
   return pushWithRedirect(to)
}

function replace(to: RouteLocationRaw) {
   return push(assign(locationAsObject(to), { replace: true }))
}

function pushWithRedirect(
    to: RouteLocationRaw | RouteLocation,
    redirectedFrom?: RouteLocation
  ): Promise<NavigationFailure | void | undefined> {
    // ...

    return (failure ? Promise.resolve(failure) : navigate(toLocation, from))/*调用navigate*/
      .catch((error: NavigationFailure | NavigationRedirectError) =>
        isNavigationFailure(error)
          ? // navigation redirects still mark the router as ready
            isNavigationFailure(error, ErrorTypes.NAVIGATION_GUARD_REDIRECT)
            ? error
            : markAsReady(error) // also returns the error
          : // reject any unknown error
            triggerError(error, toLocation, from)
      )
      .then((failure: NavigationFailure | NavigationRedirectError | void) => {
        if (failure) {
          // ...
        } else {
          // 执行finalizeNavigation完成导航
          // if we fail we don't finalize the navigation
          failure = finalizeNavigation(
            toLocation as RouteLocationNormalizedLoaded,
            from,
            true,
            replace,
            data
          )
        }
        // 触发`afterEach`
        triggerAfterEach(
          toLocation as RouteLocationNormalizedLoaded,
          from,
          failure
        )
        return failure
      })
}

function navigate(
    to: RouteLocationNormalized,
    from: RouteLocationNormalizedLoaded
  ): Promise<any> {
    let guards: Lazy<any>[]

    // ...

    // run the queue of per route beforeRouteLeave guards
    return (
      // 1.调用离开组件的`beforeRouteLeave`钩子
      runGuardQueue(guards)
        .then(() => {
          // 获取全局的的`beforeEach`钩子
          // check global guards beforeEach
          guards = []
          for (const guard of beforeGuards.list()) {
            guards.push(guardToPromiseFn(guard, to, from))
          }
          guards.push(canceledNavigationCheck)

          // 2.调用全局的`beforeEach`钩子
          return runGuardQueue(guards)
        })
        .then(() => {
          // 获取更新的路由其对应组件的`beforeRouteUpdate`钩子
          // check in components beforeRouteUpdate
          guards = extractComponentsGuards(
            updatingRecords,
            'beforeRouteUpdate',
            to,
            from
          )

          for (const record of updatingRecords) {
            record.updateGuards.forEach(guard => {
              guards.push(guardToPromiseFn(guard, to, from))
            })
          }
          guards.push(canceledNavigationCheck)

          // 3.调用复用组件的`beforeRouteUpdate`钩子
          // run the queue of per route beforeEnter guards
          return runGuardQueue(guards)
        })
        .then(() => {
          // 获取进入的路由自身的`beforeEnter`钩子
          // check the route beforeEnter
          guards = []
          for (const record of enteringRecords) {
            // do not trigger beforeEnter on reused views
            if (record.beforeEnter) {
              if (isArray(record.beforeEnter)) {
                for (const beforeEnter of record.beforeEnter)
                  guards.push(guardToPromiseFn(beforeEnter, to, from))
              } else {
                guards.push(guardToPromiseFn(record.beforeEnter, to, from))
              }
            }
          }
          guards.push(canceledNavigationCheck)

          // 4.调用新匹配路由的`beforeEnter`钩子
          // run the queue of per route beforeEnter guards
          return runGuardQueue(guards)
        })
        .then(() => {
          // NOTE: at this point to.matched is normalized and does not contain any () => Promise<Component>

          // clear existing enterCallbacks, these are added by extractComponentsGuards
          to.matched.forEach(record => (record.enterCallbacks = {}))

          // 获取进入的路由其对应组件的`beforeRouteEnter`钩子
          // check in-component beforeRouteEnter
          guards = extractComponentsGuards(
            enteringRecords,
            'beforeRouteEnter',
            to,
            from
          )
          guards.push(canceledNavigationCheck)

          // 5.调用新组件的`beforeRouteEnter`钩子
          // run the queue of per route beforeEnter guards
          return runGuardQueue(guards)
        })
        .then(() => {
          // 获取全局的的`beforeResolve`钩子
          // check global guards beforeResolve
          guards = []
          for (const guard of beforeResolveGuards.list()) {
            guards.push(guardToPromiseFn(guard, to, from))
          }
          guards.push(canceledNavigationCheck)

          // 6.调用全局的`beforeResolve`守卫
          return runGuardQueue(guards)
        })
        // catch any navigation canceled
        .catch(err =>
          isNavigationFailure(err, ErrorTypes.NAVIGATION_CANCELLED)
            ? err
            : Promise.reject(err)
        )
    )
  }
  
  // 触发`afterEach`
  function triggerAfterEach(
    to: RouteLocationNormalizedLoaded,
    from: RouteLocationNormalizedLoaded,
    failure?: NavigationFailure | void
  ): void {
    // navigation is confirmed, call afterGuards
    // TODO: wrap with error handlers
    afterGuards
      .list()
      .forEach(guard => runWithContext(() => guard(to, from, failure)))
  }

由上述源码中可以看出,由Promise then的链式调用保证了路由守卫按照以下顺序执行:

  1. 旧的路由组件beforeRouteLeave
  2. 全局配置的beforeEach
  3. 复用的路由组件beforeRouteUpdate
  4. 新路由的beforeEnter
  5. 新路由组件的beforeRouteEnter
  6. 全局配置的beforeResolve
  7. navigate执行完毕后,会调用triggerAfterEach函数,触发afterEach

和官网文档上所写的是一样的。The Full Navigation Resolution Flow

标签:vue,return,钩子,guards,failure,push,router,beforeEnter
From: https://www.cnblogs.com/beckyyyy/p/17585702.html

相关文章

  • Vue3多条数据复制功能,复制内容用逗号拼接
    <divclass="person-list"><divclass="person-item">9939939939399399</div><divclass="person-item">1111111111111111</div></div>&......
  • Vue3的响应式数据处理方式
    问题:data[0].tableId是undefined,但控制台可以打印出data[0]的值原因: Vue3的响应式数据处理方式导致的。Vue3使用了Proxy来实现响应式数据。当你访问一个响应式对象的属性时,Vue会在底层进行拦截,并返回响应式的值。这意味着,当你访问`data[0].TableId`时,Vue会返回......
  • vue3实现图片滚动播放
    <template> <divclass="swiperBox">  <divid="swiper">   <divclass="imgBox"@mouseenter="mouseenter"@mouseleave="mouseleave">    <av-for="(x,i)inLinkList&......
  • vue 页面刷新防止数据丢失的解决办法
    在vue项目中,经常会切换tag,或者刷新页面。导致路由中的数据丢失, 可以使用以下方法1:将需要缓存的数据 存在stroge(session,local)中,这样即使页面刷新也不会丢失2:将数据保存在url中,eg:{    name:'zlgmmasterdataedit',    path:'zlgmmasterdata/edit/:id/:......
  • vue2和vue3的区别
    1.性能提升vue3对性能进行了优化,相较于vue2,在运行时的性能更高。vue3采用了Proxy代理机制,使得在数据变化时可以更快的更新视图,从而提供了更好的响应性能。2.ComposiitonAPI(组合式API)vue3引入了CompsitionAPI,这是一种新的API风格,它允许开发者更好的组织和重用代码。相比于......
  • vue3状态管理工具Pinia的使用
    1.安装  npminstallpinia--save 2.src文件夹下新建store文件夹,并新建index.tsimport{createPinia}from'pinia'constpinia=createPinia()exportdefaultpinia2.在main.ts中引入piniaimportpiniafrom'./store'import{createApp}from'vue'......
  • vue3中的watch与vue2中的watch的对比
    新版的 watch 和旧版对比,在使用方式上变化非常大!旧版是这样用的,和 data 、 methods 都在同级配置://旧版的写法:exportdefault{watch:{//...},data(){return{//...}},methods:{//...}} 新版的 watch......
  • vue中vue-alipayer-v2的使用
    项目中播放视频用到了vue-alipayer-v2,代码如下<template><VueAliplayerV2:source="$api.showImageUrl+playvideo.videopath"ref="VueAliplayerV2"></VueAliplayerV2></template><scrip......
  • vue2.x接入mockJs
    1、安装npminstallmockjs2、创建文件src/mock/api、src/mock/indeximportMockfrom'mockjs'importMockApifrom"./api"Mock.setup({timeout:"300",});constmocks=[...MockApi];exportfunctionmockXHR(){for(letiofmocks)......
  • 【技术实战】Vue技术实战【三】
    需求实战一效果展示代码展示<template><divstyle="display:flex;"><divstyle="display:flex;justify-content:center;align-items:center;"><labelfor="input"style="font-family:Aria......