最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言

項目框架:Vue3 + TypeScript

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

分析

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

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

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

最后,想到了一個很笨的解決方法,輪詢。實驗過后,確定可以實現(xiàn),但就如開頭說的,這會顯得很 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 文件,添加內(nèi)容如下:(PS:具體文件路徑要結(jié)合具體的項目內(nèi)容,以下路徑及菜單格式僅作為示例)。

根據(jù)處理方式不同,有兩種方案。

方案一:使用 async 函數(shù)

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 中返回結(jié)果時,動態(tài)路由已經(jīng)加載完成。在 src/router 創(chuàng)建 index.ts 文件,添加內(nèi)容如下:

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 函數(shù)之后,登錄頁的操作將會變得很簡單。

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 函數(shù)要簡單很多,因為它不需要確保登錄后拿到結(jié)果的那一刻,路由是加載完成的。具體實現(xiàn)代碼如下:

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í)行路由跳轉(zhuǎn)命令時菜單是加載完成的。

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次,超過則說明網(wǎng)絡環(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('當前網(wǎng)絡環(huán)境較差!')
          spinning.value = false
        }
      }, 500)
    })
  })
}
// 不要忘記清除定時器
onBeforeUnmount(() => {
  clearInterval(timer.value)
  timer.value = null
})

補充

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

解決思路是添加路由前置守衛(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)路由并跳轉(zhuǎn)的實踐分享的詳細內(nèi)容,更多關于Vue添加動態(tài)路由并跳轉(zhuǎn)的資料請關注腳本之家其它相關文章!

相關文章

  • Vue實現(xiàn)導航欄菜單

    Vue實現(xiàn)導航欄菜單

    這篇文章主要為大家詳細介紹了Vue實現(xiàn)導航欄菜單,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • vue與iframe頁面數(shù)據(jù)互相通信的實現(xiàn)示例

    vue與iframe頁面數(shù)據(jù)互相通信的實現(xiàn)示例

    這篇文章主要給大家介紹了vue與iframe頁面數(shù)據(jù)互相通信的實現(xiàn)示例,文中通過代碼示例給大家介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2023-12-12
  • 使用vue.js2.0 + ElementUI開發(fā)后臺管理系統(tǒng)詳細教程(一)

    使用vue.js2.0 + ElementUI開發(fā)后臺管理系統(tǒng)詳細教程(一)

    這篇文章主要介紹了使用vue.js2.0 + ElementUI開發(fā)后臺管理系統(tǒng)詳細教程(一)的相關資料,需要的朋友可以參考下
    2017-01-01
  • vue路由傳參三種基本方式詳解

    vue路由傳參三種基本方式詳解

    這篇文章主要介紹了vue路由傳參三種基本方式詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • 詳解vue或uni-app的跨域問題解決方案

    詳解vue或uni-app的跨域問題解決方案

    這篇文章主要介紹了詳解vue或uni-app的跨域問題解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • Vue如何根據(jù)不同的路由設置不同的title標題

    Vue如何根據(jù)不同的路由設置不同的title標題

    本文主要介紹了如何在Vue路由中添加meta屬性,并以及使用router.beforeEach編寫路由前置守衛(wèi),以實現(xiàn)在路由跳轉(zhuǎn)前的一些操作,并詳細地給出了代碼示例
    2026-04-04
  • vue3+ts+element-plus 表單el-form取消回車默認提交

    vue3+ts+element-plus 表單el-form取消回車默認提交

    文章主要講述了在使用Element UI的el-form和el-input組件時,按回車鍵導致頁面刷新的問題,并提供了四種解決方法:阻止表單的默認提交事件、阻止keydown回車事件、在指定的el-input組件上阻止keydown回車事件以及在el-input中按特定組合鍵進行查找,感興趣的朋友一起看看吧
    2025-01-01
  • vue實現(xiàn)購物車全部功能的簡單方法

    vue實現(xiàn)購物車全部功能的簡單方法

    vue是前端輕量級MVVM框架,入門門檻相對較低,今天用Vue做一個購物車實例,所以下面這篇文章主要給大家介紹了關于vue實現(xiàn)購物車全部功能的簡單方法,需要的朋友可以參考下
    2021-07-07
  • vue3.0 項目搭建和使用流程

    vue3.0 項目搭建和使用流程

    這篇文章主要介紹了vue3.0 項目搭建和使用流程,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下
    2021-03-03
  • vue-cli實現(xiàn)多頁面多路由的示例代碼

    vue-cli實現(xiàn)多頁面多路由的示例代碼

    本篇文章主要介紹了vue-cli實現(xiàn)多頁面多路由的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01

最新評論

合肥市| 太谷县| 闽清县| 韶山市| 永新县| 儋州市| 台北市| 松阳县| 孙吴县| 朝阳市| 孝义市| 澎湖县| 杭锦后旗| 上栗县| 湖北省| 广德县| 奉新县| 从化市| 遂平县| 信阳市| 徐州市| 临江市| 延安市| 正宁县| 长寿区| 新野县| 佳木斯市| 静海县| 镇坪县| 六盘水市| 岑巩县| 兰坪| 秦安县| 汝南县| 长海县| 株洲市| 中阳县| 潮安县| 吉木乃县| 渑池县| 嘉荫县|