欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue登錄后添加動態(tài)路由并跳轉的實踐分享

 更新時間:2023年07月19日 10:01:48   作者:前端學習筆記_zxh  
這篇文章講給大家詳細介紹一下Vue如何實現登錄后添加動態(tài)路由并跳轉,文章通過代碼示例介紹的非常詳細,對我們的學習或工作有一定的的幫助,需要的朋友可以參考下

前言

項目框架:Vue3 + TypeScript

有這樣一個需求,系統(tǒng)默認只有最基礎的幾個路由,如登錄、404等,其它路由需要在登錄后動態(tài)添加。系統(tǒng)沒有固定首頁,登錄完成后跳轉至動態(tài)菜單的第一個菜單頁。

分析

這一邏輯乍一看很簡單,其實有很多小坑在里面。其中最容易踩的的坑是動態(tài)路由尚未渲染完成就已經觸發(fā)路由跳轉了,這時候肯定是404,因為路由并不存在;另一個容易踩的坑是路由重復加載,此時頁面會顯示空白,需要手動刷新才能正常顯示。

首先想到的就是使用 Promise 函數解決,結果行不通。addRoute 是一個宏任務 和 resolve 是微任務,所以 Promise 結束的時候并不能代表動態(tài)路由已經添加完成。

其次又想到使用 async 函數來確保獲取到登錄成功結果的時候,路由已經添加完成,結果一番嘗試后依然行不通。因為添加路由的操作不是異步的,沒有返回 Promise 對象,因此這里的 await 是不會產生效果的。(PS:事后使用 Promise.all 解決了這一問題,后面的具體方法上會說。)

最后,想到了一個很笨的解決方法,輪詢。實驗過后,確定可以實現,但就如開頭說的,這會顯得很 low ,雖然它最終解決了問題。

實踐

登錄的操作都是一樣的,所以單獨拿出來只寫一遍。表單就不做介紹了,就從點擊登錄表單校驗通過后說起。

所有登錄的代碼放到一個頁面會顯得臃腫,所以具體登錄的操作邏輯我把它抽離了出來。在 src/utils 目錄下創(chuàng)建一個 auth.ts 文件。

auth.ts

import { useRouteListStore } from '@/store/router'
const routeListStore = useRouteListStore()
// 登錄
export async function Login(data: { username: string; password: string; portal: string; corpCode: string }) {
  const { username, password, portal, corpCode } = data
  try {
    // 登錄接口
    const res = await getLogin({ username, password, portal, corpCode })
    // ...
    // 這里寫保存用戶信息及 token 的邏輯
    // ...
    // 添加路由操作,寫在 pinia 中,后面會說
    await routeListStore.updateRouteList()
    return res
  } catch (err) {
    return err
  }
}

接下來要寫添加路由的具體邏輯。在 src/store 目錄下創(chuàng)建一個 router.ts 文件,添加內容如下:(PS:具體文件路徑要結合具體的項目內容,以下路徑及菜單格式僅作為示例)。

根據處理方式不同,有兩種方案。

方案一:使用 async 函數

src/store/router.ts

export const useRouteListStore = defineStore('routeList', {
  state: () => ({
    routeList: [],
    breadcrumb: [],
    getRouter: true // 是否需要重新加載路由
  }),
  actions: {
    // 更新菜單并追加路由
    async updateRouteList() {
      const modules = import.meta.glob('../views/**/*.vue')
      // 此為接口請求獲取的菜單
      const list = await getMenus()
      list.forEach((e) => {
        e.route = e.path
        e.component = () => import('@/layout/index.vue')
        e.redirect = `${e.path}/${e.children[0].path}`
        e.children.forEach((item) => {
          item.route = `${e.path}/${item.path}`
          item.component = modules[`../views${item.component}.vue`]
        })
      })
      await addRouteList(list)
      this.getRouter = false
      this.routeList = list
      return true
    },
  }
})

接下來寫動態(tài)添加路由的邏輯,使用 Promise.all 來確保 Pinia 中返回結果時,動態(tài)路由已經加載完成。在 src/router 創(chuàng)建 index.ts 文件,添加內容如下:

src/router/index.ts

export function addRouteList(data: any[] = []) {
  return new Promise((resolve) => {
    const promises = []
    data.forEach((e) => promises.push(router.addRoute(e)))
    Promise.all(promises).then(() => resolve(true))
  })
}

使用 async 函數之后,登錄頁的操作將會變得很簡單。

login.vue

import { Login } from '@/utils/auth'
const onSubmit = () => {
  validate().then(() => {
    Login(formState).then(() => {
      router.push(routerStore.routeList[0].path)
    }).catch(err => {
      message.error(err.message)
    })
  })
}

方案二:使用輪詢

輪詢的方案相比于使用 async 函數要簡單很多,因為它不需要確保登錄后拿到結果的那一刻,路由是加載完成的。具體實現代碼如下:

src/store/router.ts

export const useRouteListStore = defineStore('routeList', {
  state: () => ({
    routeList: [],
    breadcrumb: [],
    getRouter: true
  }),
  actions: {
    // 更新菜單并追加路由
    updateRouteList() {
      listMenus().then((res) => {
        const list = res.data
        if (list === null) {
          this.getRouter = false
          router.push('/404')
          return
        }
        list.forEach((e) => {
          e.route = e.path
          e.component = () => import('@/layout/index.vue')
          e.children.forEach((item) => {
            item.route = `${e.path}/${item.path}`
            item.component = modules[`../views${item.component}.vue`]
          })
        })
        addRouteList(list)
        this.getRouter = false
        this.routeList = list
      })
  }
})

src/router/index.ts

export function addRouteList(data: any[] = []) {
  data.forEach((e) => {
    router.addRoute(e)
  })
}

輪詢的好處是邏輯簡單,唯一麻煩的一點就是在登錄后添加一個定時器去定期獲取路由是否加載完成。之所以要加定時器是因為獲取菜單是異步請求,而程序執(zhí)行時很快的,所以要確保執(zhí)行路由跳轉命令時菜單是加載完成的。

login.vue

import { ref, onBeforeUnmount } from 'vue'
import { useRouter } from 'vue-router'
import { useRouteListStore } from '@/store/router'
const routerStore = useRouteListStore()
import { Login } from '@/utils/auth'
const router = useRouter()
// 每0.5s判斷一次菜單是否加載完成,最多判斷30次,超過則說明網絡環(huán)境極差
const timer = ref(null)
const onSubmit = () => {
  validate().then(() => {
    Login(formState).then(() => {
    let i = 0
      timer.value = setInterval(() => {
        if (routerStore.routeList[0].path) {
          router.push(routerStore.routeList[0].path)
        }
        i++
        if (i > 30) {
          clearInterval(timer.value)
          timer.value = null
          i = null
          message.error('當前網絡環(huán)境較差!')
          spinning.value = false
        }
      }, 500)
    })
  })
}
// 不要忘記清除定時器
onBeforeUnmount(() => {
  clearInterval(timer.value)
  timer.value = null
})

補充

以上代碼只能保證系統(tǒng)初次登錄后可以正常跳轉頁面,如果退出當前賬號,重新登錄或者更換賬號登錄,會出現路由重復加載的問題,也就是文章開頭所說的另一個容易踩的坑。這個坑解決起來并不困難,只要注意到了,很容易就可以解決。

解決思路是添加路由前置守衛(wèi),同時在 Pinia 中添加一個字段判斷當前路由是否需要重新加載即可。具體代碼如下:

import Cookies from 'js-cookie'
import { useRouteListStore } from '@/store/router'
// 前置守衛(wèi)
router.beforeEach(async (to, from, next) => {
  const token = Cookies.get('token')
  if (!token) {
    next({ path: '/login' })
  } else {
    const routerStore = useRouteListStore()
    routerStore.addBreadcrumb(to)
    // 判斷菜單是否存在且是否需要重新加載
    if (routerStore.routeList.length === 0 && routerStore.getRouter) {
      await routerStore.updateRouteList()
      next({ path: to.path, query: to.query })
    } else {
      next()
    }
  }
})

如對本文有疑問或不同看法,歡迎在評論區(qū)指出。

以上就是Vue登錄后添加動態(tài)路由并跳轉的實踐分享的詳細內容,更多關于Vue添加動態(tài)路由并跳轉的資料請關注腳本之家其它相關文章!

相關文章

  • vue自適應布局postcss-px2rem詳解

    vue自適應布局postcss-px2rem詳解

    這篇文章主要介紹了vue自適應布局(postcss-px2rem)的相關知識,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2022-05-05
  • vue3+ts+EsLint+Prettier規(guī)范代碼的方法實現

    vue3+ts+EsLint+Prettier規(guī)范代碼的方法實現

    本文主要介紹在Vue3中使用TypeScript做開發(fā)時,如何安裝與配置EsLint和Prettier,以提高編碼規(guī)范。感興趣的可以了解一下
    2021-10-10
  • vue 中 get / delete 傳遞數組參數方法

    vue 中 get / delete 傳遞數組參數方法

    這篇文章主要介紹了vue 中 get / delete 傳遞數組參數方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • vue3.x使用swiper實現卡片輪播

    vue3.x使用swiper實現卡片輪播

    這篇文章主要為大家詳細介紹了vue3.x使用swiper實現卡片輪播,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Vue3使用indexDB緩存靜態(tài)資源的示例代碼

    Vue3使用indexDB緩存靜態(tài)資源的示例代碼

    IndexedDB 是一個瀏覽器內建的數據庫,它可以存放對象格式的數據,默認情況下,瀏覽器會將自身所在的硬盤位置剩余容量全部作為indexedDB的存儲容量,本文給大家介紹了Vue3使用indexDB緩存靜態(tài)資源,需要的朋友可以參考下
    2024-10-10
  • Monaco-editor 的 JSON Schema 配置及使用介紹

    Monaco-editor 的 JSON Schema 配置及使用介紹

    這篇文章主要為大家介紹了Monaco-editor 的 JSON Schema 配置及使用介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • antd vue表格可編輯單元格以及求和實現方式

    antd vue表格可編輯單元格以及求和實現方式

    這篇文章主要介紹了antd vue表格可編輯單元格以及求和實現方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • vue如何獲取光標位置

    vue如何獲取光標位置

    這篇文章主要介紹了vue獲取光標位置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Vue組件傳參11種方式舉例介紹

    Vue組件傳參11種方式舉例介紹

    這篇文章主要給大家介紹了關于Vue組件傳參11種方式的相關資料,文中通過代碼示例介紹的非常詳細,對大家學習或者使用vue具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • 利用Vue與D3.js創(chuàng)建交互式數據可視化

    利用Vue與D3.js創(chuàng)建交互式數據可視化

    在現代Web開發(fā)中,數據可視化是一個引人矚目的熱點領域,從簡單的圖表到復雜的交互式儀表盤,數據可視化能夠幫助用戶更好地理解數據,而Vue與D3.js的結合則為我們提供了構建這些可視化效果的強大工具,本文將向您展示如何利用Vue與D3.js創(chuàng)建一個基本的交互式數據可視化項目
    2025-02-02

最新評論