亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

vue3+vue-router+vite實(shí)現(xiàn)動(dòng)態(tài)路由的全過程

 更新時(shí)間:2024年10月24日 10:38:45   作者:YuShiYue  
動(dòng)態(tài)路由是根據(jù)不同情況實(shí)時(shí)變化的路由,在權(quán)限管理系統(tǒng)中,動(dòng)態(tài)路由常用于根據(jù)用戶角色分配不同的菜單和功能,這篇文章主要介紹了vue3+vue-router+vite實(shí)現(xiàn)動(dòng)態(tài)路由的相關(guān)資料,需要的朋友可以參考下

什么是動(dòng)態(tài)路由

什么場景會(huì)用到動(dòng)態(tài)路由

舉一個(gè)最常見的例子,比如說我們要開發(fā)一個(gè)后臺(tái)管理系統(tǒng),一般來說后臺(tái)管理系統(tǒng)都會(huì)分角色登錄,這個(gè)時(shí)候也就涉及到了權(quán)限,比如說這個(gè)后臺(tái)管理系統(tǒng)現(xiàn)在有超級管理員,管理員,運(yùn)維,財(cái)務(wù)等這幾個(gè)角色,每個(gè)角色登錄系統(tǒng)之后都會(huì)有不同的權(quán)限,超級管理員需要所有的權(quán)限,財(cái)務(wù)可能只需要財(cái)務(wù)相關(guān)的模塊(菜單)以及按鈕等,通常實(shí)現(xiàn)這種需求會(huì)有以下常見方案

路由表由前端去維護(hù)

也就是說我們已知這幾個(gè)角色分別對應(yīng)哪些權(quán)限,前端寫好路由配置表,,后端只需要告訴你當(dāng)前登錄人是屬于哪個(gè)角色,前端根據(jù)角色類型去寫一個(gè)過濾函數(shù),獲取該角色所擁有的菜單以及按鈕,然后動(dòng)態(tài)的去添加路由,這樣做有一個(gè)缺點(diǎn)就是,如果又增加了一個(gè)新的角色怎么辦?某個(gè)角色想增加一些權(quán)限怎么辦?這個(gè)時(shí)候前端就需要去新增或者修改代碼,一點(diǎn)也不友好

路由表的數(shù)據(jù)由后端返回

這種也是常用的一種方式,可能我們的系統(tǒng)里面需要開發(fā)一些功能,如菜單管理,角色管理,用戶管理等,也就是常說的權(quán)限中心,前端開發(fā)完的頁面所對應(yīng)的路由信息有后端去維護(hù),這個(gè)時(shí)候我們在開發(fā)的時(shí)候需要約束某一種規(guī)則,比如所有頁面都放到/src/views目標(biāo)下面,然后通過菜單管理去維護(hù)數(shù)據(jù),維護(hù)完的數(shù)據(jù)可以到角色管理里面去配置角色菜單,配置完角色,可以到用戶管理里面給某個(gè)用戶配置角色等一些列流程,這樣的話即使新增一個(gè)角色,或者修改一個(gè)角色的角色菜單,前端都不需要去修改代碼,只要在菜單管理里面維護(hù)好了數(shù)據(jù),想怎么改怎么改,后端返回的數(shù)據(jù)格式可能如下:

[
  {
    path: "/application",
    name: "application",
    component: "Layout",
    title: "應(yīng)用管理",
    show: true,
    icon: "",
    children: [
      {
        path: "",
        name: "application-index",
        component: "/application/index.vue",
      },
    ],
  },
  {
    path: "/permission",
    name: "permission",
    component: "Layout",
    title: "權(quán)限管理",
    show: true,
    icon: "",
    children: [
      {
        path: "menu",
        name: "permission-menu",
        component: "/permission/menu/index.vue",
        title: "菜單管理",
        show: true,
        icon: "",
      },
      {
        path: "user",
        name: "permission-user",
        component: "/permission/user/index.vue",
        title: "用戶管理",
        show: true,
        icon: "",
      },
      {
        path: "role",
        name: "permission-role",
        component: "/permission/role/index.vue",
        title: "角色管理",
        show: true,
        icon: "",
      },
    ],
  },
]

其實(shí)仔細(xì)觀察這個(gè)數(shù)據(jù)結(jié)構(gòu),是不是有點(diǎn)熟悉,path,name,component,children,我們好像手動(dòng)維護(hù)路由表的時(shí)候也會(huì)用到這些屬性

如何實(shí)現(xiàn)動(dòng)態(tài)路由

實(shí)現(xiàn)動(dòng)態(tài)路由其實(shí)就要用到vue-router提供的一個(gè)方法,叫addRoute在之前版本的時(shí)候是addRoutes,現(xiàn)在非版本的vue-router給廢除了
addRoute()如何使用呢?可以看一下官方文檔

當(dāng)我們添加一個(gè)主路由的時(shí)候

router.addRoute({ path: '/permission', name: 'permission', component: () => import('xxxxx')})

添加子路由也就是嵌套路由

router.addRoute('主路由的name', { path: 'settings', component: AdminSettings })

既然我們已經(jīng)知道了addRoute()方法如何使用,下面我們就可以去實(shí)現(xiàn)這部分邏輯

我們看一下官方文檔的導(dǎo)航守衛(wèi)里面的內(nèi)容

在之前我們使用導(dǎo)航守衛(wèi)的時(shí)候需要一個(gè)參數(shù)next()去控制是否放行以及去哪個(gè)頁面,但是在新版本的vue-router里面可以不是用next(),當(dāng)然你是用也行~

我們可以新建一個(gè)permission.ts文件

import router from "./index";
import { useSessionStorage } from "@vueuse/core";
import { StorageEnum } from "@/enum";
import { useUserStore } from "@/store";

const whiteList = ["/login", "/404"];

router.beforeEach(async (to) => {
  const token = useSessionStorage(StorageEnum.TOKEN, "").value;
  // 如果在白名單里面 并且 token 不存在
  if (whiteList.includes(to.path) && !token) {
    return true;
  } else {
    const { menuList, getMenuList } = useUserStore();
    // 如果為空數(shù)組,name就請求接口重新獲取后端維護(hù)的路由數(shù)據(jù)
    if (!menuList.length) {
      await getMenuList();

      console.log("獲取全部路由 =>", router.getRoutes());
      // 觸發(fā)重定向 不這樣寫會(huì)導(dǎo)致刷新找不到路由 兩種寫法都行
      // return { path: to.fullPath };
      return to.fullPath;
    }
  }
});

這里我們可以看到一會(huì)return true一會(huì)return to.fullpath是為什么,通過官方導(dǎo)航守衛(wèi)里面的介紹,我們可以知道的是

通過官方文檔動(dòng)態(tài)路由,我們可以直到

所以說return to.fullpath是官方告訴我們要這么使用,也是為了解決動(dòng)態(tài)路由頁面刷新的時(shí)候會(huì)出現(xiàn)頁面空白或者404的問題
出現(xiàn)404的話比如說你在路由表中維護(hù)了下面路由映射

{
 path: "/:pathMatch(.*)",
  name: "page404",
  component: () => import("@/views/system/404.vue"),
}

上面說的主要是在全局導(dǎo)航守衛(wèi)里面的一些使用及注意事項(xiàng),我們可以看到并沒有用到addRoute()這個(gè)方法,也沒有出現(xiàn)拿到后端數(shù)據(jù)前端轉(zhuǎn)換成路由表的相關(guān)代碼,但是我們可以看到有一個(gè)getMenuList()函數(shù),我們在開發(fā)的時(shí)候,肯定是要考慮到復(fù)用以及復(fù)雜邏輯抽取的問題,一個(gè)動(dòng)態(tài)路由的實(shí)現(xiàn)會(huì)牽扯到很多知識(shí)點(diǎn)接口請求,vuex或者pinia狀態(tài)維護(hù),vue-router,vite里面怎么獲取文件等下面看一下如何獲取到接口給的數(shù)據(jù),轉(zhuǎn)換成vue-router能夠識(shí)別的數(shù)據(jù)首先我們要看一個(gè)vite官方給提供的功能,我們拿到后端給的文件路徑如上面代碼出現(xiàn)的component字段,如/application/index.vue,這個(gè)文件可能在我們本地項(xiàng)目中的src/views/application/index.vue這個(gè)路徑下

我們需要把它轉(zhuǎn)換成一個(gè)下面的格式() => import('xxxx'),我們需要?jiǎng)討B(tài)的去拼接獲取文件,該怎么實(shí)現(xiàn)呢?

vite官方文檔中有說明

需要使用import.meta.glob,這個(gè)時(shí)候我們可以打印一下import.meta.glob("../views/**"),看一下返回的到底是什么

返回的是一個(gè)對象,而對象的key我們可以拼接獲取到,而value正是我們想要的動(dòng)態(tài)獲取的文件路徑

以下代碼僅供參考,有很多需要完善的地方,只為演示使用

import type { RouterType } from "@/router/type";
import router from "@/router";
import type { RouteRecordRaw } from "vue-router";

export const useRouterConfig = () => {
	// 獲取views目錄下的所有的文件 不要使用@別名 
  const modules = import.meta.glob("../views/**");
  const asyncRoutes = ref<RouterType[]>([]);

  const addRoutes = (menus: RouterType[]) => {
    asyncRoutes.value = menus;
    filterAsyncRouter();
    // 動(dòng)態(tài)添加 / 路由
    router.addRoute({
      path: "/",
      redirect: asyncRoutes.value[0].path,
    });
  };

  const filterAsyncRouter = () => {
    const routerLoop = (routes: RouterType[], ParentName?: string) => {
      routes.forEach((item) => {
        if (item.component === "Layout") {
          item.component = () => import("@/layout/index.vue");
        } else {
          item.component = resolveComponent(item.component);
        }
        const { title, show, icon, name, path, component, children } = item;
        const route: RouteRecordRaw = {
          component,
          path,
          name,
          meta: {
            title,
            show,
            icon,
          },
          children: children as any,
        };
		
		// 動(dòng)態(tài)添加路由
        if (ParentName) {
          router.addRoute(ParentName, route);
        } else {
          router.addRoute(route);
        }

        if (item.children && item.children.length > 0) {
          routerLoop(item.children, item.name);
        }
      });
    };

    routerLoop(asyncRoutes.value);
  };

  const resolveComponent = (path: string) => {
    console.log(modules);
    // 拿到views下面的所有文件之后,動(dòng)態(tài)拼接`key`去獲取value
    const importPage = modules[`../views${path}`];
    if (!importPage) {
      throw new Error(
        `Unknown page ${path}. Is it located under Pages with a .vue extension?`
      );
    }
    return importPage;
  };

  return { addRoutes };
};

綜上所述:

要想實(shí)現(xiàn)vite+vue-router實(shí)現(xiàn)動(dòng)態(tài)路由我們需要用到

  • addRoute()
  • import.meta.glob()
  • 獲取后端tree數(shù)據(jù),遞歸循環(huán),可能業(yè)務(wù)會(huì)有type類型,比如分為模塊,菜單,頁面,按鈕等,到時(shí)候結(jié)合業(yè)務(wù)去實(shí)現(xiàn)邏輯
  • 導(dǎo)航守衛(wèi)使用時(shí)的注意事項(xiàng),否則會(huì)出現(xiàn)刷新白屏,或者路由訪問死循環(huán)等

總結(jié) 

到此這篇關(guān)于vue3+vue-router+vite實(shí)現(xiàn)動(dòng)態(tài)路由的文章就介紹到這了,更多相關(guān)vue-router+vite動(dòng)態(tài)路由內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論