中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue中的路由導航及守衛導航源碼分析

發布時間:2023-04-20 09:31:27 來源:億速云 閱讀:80 作者:iii 欄目:開發技術

這篇文章主要介紹“Vue中的路由導航及守衛導航源碼分析”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Vue中的路由導航及守衛導航源碼分析”文章能幫助大家解決問題。

    全局前置守衛

    你可以使用 router.beforeEach 注冊一個全局前置守衛:

    const router = createRouter({ ... })
    router.beforeEach((to, from) => {
      // ...
      // 返回 false 以取消導航
      return false
    })

    當一個導航觸發時,全局前置守衛按照創建順序調用。守衛是異步解析執行,此時導航在所有守衛 resolve 完之前一直處于等待中。

    每個守衛方法接收兩個參數:

    • to: 即將要進入的目標

    • from: 當前導航正要離開的路由

    可以返回的值如下:

    • false: 取消當前的導航。如果瀏覽器的 URL 改變了(可能是用戶手動或者瀏覽器后退按鈕),那么 URL 地址會重置到 from 路由對應的地址。

    • 一個路由地址: 通過一個路由地址跳轉到一個不同的地址,就像你調用 router.push() 一樣,你可以設置諸如 replace: truename: 'home' 之類的配置。當前的導航被中斷,然后進行一個新的導航,就和 from 一樣。

     router.beforeEach(async (to, from) => {
       if (
         // 檢查用戶是否已登錄
         !isAuthenticated &&
         // ?? 避免無限重定向
         to.name !== 'Login'
       ) {
         // 將用戶重定向到登錄頁面
         return { name: 'Login' }
       }
     })

    如果遇到了意料之外的情況,可能會拋出一個 Error。這會取消導航并且調用 router.onError() 注冊過的回調。

    如果什么都沒有,undefined 或返回 true,則導航是有效的,并調用下一個導航守衛

    以上所有都同 async 函數 和 Promise 工作方式一樣:

    router.beforeEach(async (to, from) => {
      // canUserAccess() 返回 `true` 或 `false`
      const canAccess = await canUserAccess(to)
      if (!canAccess) return '/login'
    })

    可選的第三個參數 next

    在之前的 Vue Router 版本中,也是可以使用 第三個參數 next 的。這是一個常見的錯誤來源,可以通過 RFC 來消除錯誤。然而,它仍然是被支持的,這意味著你可以向任何導航守衛傳遞第三個參數。在這種情況下,確保 next 在任何給定的導航守衛中都被嚴格調用一次。它可以出現多于一次,但是只能在所有的邏輯路徑都不重疊的情況下,否則鉤子永遠都不會被解析或報錯。這里有一個在用戶未能驗證身份時重定向到/login的錯誤用例:

    // BAD
    router.beforeEach((to, from, next) => {
      if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
      // 如果用戶未能驗證身份,則 `next` 會被調用兩次
      next()
    })

    下面是正確的版本:

    // GOOD
    router.beforeEach((to, from, next) => {
      if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
      else next()
    })

    全局解析守衛

    你可以用 router.beforeResolve 注冊一個全局守衛。這和 router.beforeEach 類似,因為它在 每次導航時都會觸發,但是確保在導航被確認之前,同時在所有組件內守衛和異步路由組件被解析之后,解析守衛就被正確調用。這里有一個例子,確保用戶可以訪問自定義 meta屬性 requiresCamera 的路由:

    路由元信息

    有時,你可能希望將任意信息附加到路由上,如過渡名稱、誰可以訪問路由等。這些事情可以通過接收屬性對象的meta屬性來實現,并且它可以在路由地址和導航守衛上都被訪問到。定義路由的時候你可以這樣配置 meta 字段:

    const routes = [
      {
        path: '/posts',
        component: PostsLayout,
        children: [
          {
            path: 'new',
            component: PostsNew,
            // 只有經過身份驗證的用戶才能創建帖子
            meta: { requiresAuth: true }
          },
          {
            path: ':id',
            component: PostsDetail
            // 任何人都可以閱讀文章
            meta: { requiresAuth: false }
          }
        ]
      }
    ]

    那么如何訪問這個 meta 字段呢?

    首先,我們稱呼 routes 配置中的每個路由對象為 路由記錄。路由記錄可以是嵌套的,因此,當一個路由匹配成功后,它可能匹配多個路由記錄。

    例如,根據上面的路由配置,/posts/new 這個 URL 將會匹配父路由記錄 (path: '/posts') 以及子路由記錄 (path: 'new')。

    一個路由匹配到的所有路由記錄會暴露為 $route 對象(還有在導航守衛中的路由對象)的$route.matched 數組。我們需要遍歷這個數組來檢查路由記錄中的 meta 字段,但是 Vue Router 還為你提供了一個 $route.meta 方法,它是一個非遞歸合并所有 meta 字段的(從父字段到子字段)的方法。這意味著你可以簡單地寫

    router.beforeEach((to, from) => {
      // 而不是去檢查每條路由記錄
      // to.matched.some(record => record.meta.requiresAuth)
      if (to.meta.requiresAuth && !auth.isLoggedIn()) {
        // 此路由需要授權,請檢查是否已登錄
        // 如果沒有,則重定向到登錄頁面
        return {
          path: '/login',
          // 保存我們所在的位置,以便以后再來
          query: { redirect: to.fullPath },
        }
      }
    })

    TypeScript

    可以通過擴展 RouteMeta 接口來輸入 meta 字段:

    // typings.d.ts or router.ts
    import 'vue-router'
    declare module 'vue-router' {
      interface RouteMeta {
        // 是可選的
        isAdmin?: boolean
        // 每個路由都必須聲明
        requiresAuth: boolean
      }
    }

    router.beforeResolve

    router.beforeResolve(async to => {
      if (to.meta.requiresCamera) {
        try {
          await askForCameraPermission()
        } catch (error) {
          if (error instanceof NotAllowedError) {
            // ... 處理錯誤,然后取消導航
            return false
          } else {
            // 意料之外的錯誤,取消導航并把錯誤傳給全局處理器
            throw error
          }
        }
      }
    })

    router.beforeResolve 是獲取數據或執行任何其他操作(如果用戶無法進入頁面時你希望避免執行的操作)的理想位置。

    全局后置鉤子

    你也可以注冊全局后置鉤子,然而和守衛不同的是,這些鉤子不會接受 next 函數也不會改變導航本身:

    router.afterEach((to, from) => {
      sendToAnalytics(to.fullPath)
    })

    它們對于分析、更改頁面標題、聲明頁面等輔助功能以及許多其他事情都很有用。

    它們也反映了 navigation failures 作為第三個參數:

    js

    router.afterEach((to, from, failure) => {
      if (!failure) sendToAnalytics(to.fullPath)
    })

    了解更多關于 navigation failures 的信息在它的指南中。

    路由獨享的守衛

    你可以直接在路由配置上定義 beforeEnter 守衛:

    const routes = [
      {
        path: '/users/:id',
        component: UserDetails,
        beforeEnter: (to, from) => {
          // reject the navigation
          return false
        },
      },
    ]

    beforeEnter 守衛 只在進入路由時觸發,不會在 paramsqueryhash 改變時觸發。例如,從 /users/2 進入到 /users/3 或者從 /users/2#info 進入到 /users/2#projects。它們只有在 從一個不同的 路由導航時,才會被觸發。

    你也可以將一個函數數組傳遞給 beforeEnter,這在為不同的路由重用守衛時很有用:

    function removeQueryParams(to) {
      if (Object.keys(to.query).length)
        return { path: to.path, query: {}, hash: to.hash }
    }
    function removeHash(to) {
      if (to.hash) return { path: to.path, query: to.query, hash: '' }
    }
    const routes = [
      {
        path: '/users/:id',
        component: UserDetails,
        beforeEnter: [removeQueryParams, removeHash],
      },
      {
        path: '/about',
        component: UserDetails,
        beforeEnter: [removeQueryParams],
      },
    ]

    請注意,你也可以通過使用``路徑 meta 字段和全局導航守衛`來實現類似的行為。

    組件內的守衛

    最后,你可以在路由組件內直接定義路由導航守衛(傳遞給路由配置的)

    可用的配置 API

    你可以為路由組件添加以下配置:

    • beforeRouteEnter

    • beforeRouteUpdate

    • beforeRouteLeave

    const UserDetails = {
      template: `...`,
      beforeRouteEnter(to, from) {
        // 在渲染該組件的對應路由被驗證前調用
        // 不能獲取組件實例 `this` !
        // 因為當守衛執行時,組件實例還沒被創建!
      },
      beforeRouteUpdate(to, from) {
        // 在當前路由改變,但是該組件被復用時調用
        // 舉例來說,對于一個帶有動態參數的路徑 `/users/:id`,在 `/users/1` 和 `/users/2` 之間跳轉的時候,
        // 由于會渲染同樣的 `UserDetails` 組件,因此組件實例會被復用。而這個鉤子就會在這個情況下被調用。
        // 因為在這種情況發生的時候,組件已經掛載好了,導航守衛可以訪問組件實例 `this`
      },
      beforeRouteLeave(to, from) {
        // 在導航離開渲染該組件的對應路由時調用
        // 與 `beforeRouteUpdate` 一樣,它可以訪問組件實例 `this`
      },
    }

    beforeRouteEnter 守衛 不能 訪問 this,因為守衛在導航確認前被調用,因此即將登場的新組件還沒被創建。

    不過,你可以通過傳一個回調給 next 來訪問組件實例。在導航被確認的時候執行回調,并且把組件實例作為回調方法的參數:

    beforeRouteEnter (to, from, next) {
      next(vm => {
        // 通過 `vm` 訪問組件實例
      })
    }

    注意 beforeRouteEnter 是支持給 next 傳遞回調的唯一守衛。對于 beforeRouteUpdatebeforeRouteLeave 來說,this 已經可用了,所以不支持 傳遞回調,因為沒有必要了:

    beforeRouteUpdate (to, from) {
      // just use `this`
      this.name = to.params.name
    }

    這個 離開守衛 通常用來預防用戶在還未保存修改前突然離開。該導航可以通過返回 false 來取消。

    beforeRouteLeave (to, from) {
      const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
      if (!answer) return false
    }

    使用組合 API

    如果你正在使用組合 API 和 setup 函數來編寫組件,你可以通過 onBeforeRouteUpdateonBeforeRouteLeave 分別添加 update 和 leave 守衛。

    完整的導航解析流程

    • 導航被觸發。

    • 在失活的組件里調用 beforeRouteLeave 守衛。

    • 調用全局的 beforeEach 守衛。

    • 在重用的組件里調用 beforeRouteUpdate 守衛(2.2+)。

    • 在路由配置里調用 beforeEnter。

    • 解析異步路由組件。

    • 在被激活的組件里調用 beforeRouteEnter。

    • 調用全局的 beforeResolve 守衛(2.5+)。

    • 導航被確認。

    • 調用全局的 afterEach 鉤子。

    • 觸發 DOM 更新。

    • 調用 beforeRouteEnter 守衛中傳給 next 的回調函數,創建好的組件實例會作為回調函數的參數傳入。

    關于“Vue中的路由導航及守衛導航源碼分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    vue
    AI

    涪陵区| 武胜县| 交口县| 宁德市| 徐州市| 青神县| 万州区| 朝阳区| 华蓥市| 甘德县| 朝阳市| 广饶县| 凤凰县| 洛隆县| 平利县| 且末县| 壶关县| 合肥市| 利津县| 长海县| 延吉市| 温州市| 双城市| 中阳县| 临安市| 静海县| 延边| 苍溪县| 安多县| 湖北省| 开封市| 偏关县| 巧家县| 封丘县| 临颍县| 临汾市| 循化| 长宁县| 井冈山市| 昭觉县| 天峻县|