Vite + Vue3 動態路由 - 踩坑記錄

Slowlyo發表於2022-06-09

常見的幾個問題

  • 重新整理頁面空白
    • addRoute 沒有載入完成就訪問 -> next() 改成 next({…to, replace: true})
    • 路由重名, 檢查路由的name是否有重複
  • 路由守衛死迴圈
    • 新增一些條件, 比如: 判斷是否已經獲取到了路由資料
  • 重新整理頁面會跳轉到404頁面
    • 在動態路由新增完成後, 再新增404的路由
  • Vite 的元件懶載入
    const viteComponent = import.meta.glob("../views/**/*.vue")
    // ...
    component: viteComponent[`../views${item.path}.vue`]


貼一下路由守衛部分的程式碼

// 路由守衛
router.beforeEach((to, from, next) => {
    //在跳轉路由之前,先清除所有的請求
    clearPending()

    // 判斷是否登入
    if (to.path === "/login") {
        next()
    } else {
        let token = getToken()
        if (token && typeof token != "undefined") {
            // 如果vuex中沒有路由資料,則獲取路由資料
            if (store.state.menus.length === 0) {
                // 非同步 確保路由已經新增完成 (貌似不需要)
                getRouters().then(() => {
                    next({
                        ...to, // 無限訪問目標路由, 直到 addRoute() 新增完成
                        replace: true, // 本次操作後,不能透過瀏覽器後退按鈕,返回前一個路由
                    })
                })
            } else {
                next()
            }
        } else {
            next("/login")
        }
    }
})

// 獲取路由資料
const getRouters = () => {
    return new Promise((resolve) => {
        // 請求路由資料
        systemMenu.list().then((res) => {
            // 存入vuex
            store.dispatch("initMenu", res.data).then(() => {
                // 處理路由資料
                let data = handlerRouterDate(res.data)
                // 新增路由
                data.forEach((item: any) => {
                    router.addRoute("base", item)
                })

                // 在動態路由新增完成後, 才新增 404路由 否則會跳轉到404頁面
                router.addRoute("base", {
                    path: "/:w+",
                    name: "404Page",
                    component: () => import("@/views/404.vue"),
                })

                // 返回成功
                resolve(null)
            })
        })
    })
}

// 處理路由資料
const handlerRouterDate = (data: any) => {
    let routerData = <any>[]

    // 遍歷路由資料
    data.forEach((item: any) => {
        if (item.children) {
            // 遞迴處理子路由
            let temp = handlerRouterDate(item.children)
            // 處理完成後,新增到同一級返回
            temp.forEach((sub: any) => {
                if (sub.router != "-") {
                    routerData.push(sub)
                }
            })
        }

        if (item.router != "-") {
            // 處理路由資料格式
            routerData.push(handlerRouterItem(item))
        }
    })

    return routerData
}

// 處理單個路由資料
const handlerRouterItem = (item: any) => {
    return {
        path: item.router,
        name: item.name,
        // webpack 用以下方式引入
        // component: () => import(`@/views${item.path}.vue`)
        // vite 需要以下方式引入
        component: viteComponent[`../views${item.path}.vue`],
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結
海到無涯天作案,山登絕頂我為峰

相關文章