vue3+vite2实现动态路由并且动态加载组件,避坑上线成功

因为项目中的需求菜单的生成由后端返回的个人信息进行配置,所以就使用了动态路由这个方法去实现项目菜单的动态加载,这一功能的完成主要涉及两个方面

一:动态路由的生成

这一部分我主要是在全局路由守卫中完成的,因为路由信息是后端返回的,所以使用async await,在获取菜单之后对路由对象进行封装,为了避免顶层使用await,我选择在路由全局守卫中进行对路由的封装和添加

router/index.js

import {createRouter, createWebHistory} from 'vue-router';
import routes from "./router";
import { useMainStore } from '../store';
import { commonApi } from '../API';

const router = createRouter({
    history: createWebHistory(),
    routes: routes
});
router.beforeEach(async(to, from, next) => {
    const store = useMainStore()

    if(to.fullPath!==""&&to.fullPath!=="/"){
        //记录当前路由
        store.selectedMenu = to.fullPath;
    }
    if(routes.length===1){
        if(store.menuList.length===0){
            //页面刷新时重新获取用户信息,保存菜单
            await store.getUserInfo()
            store.isRefreshMenu =true;
        }
        //封装动态路由对象

        let route = {
            path:"/",
            name:'home',
            redirect:store.menuList[0].menuUrl,
             component:()=>import(/* @vite-ignore */"../views/main.vue"),
            // component:defineAsyncComponent(()=>import(/* @vite-ignore */'../views/main')),
            children:[]
        }
        //加载组件形成映射对象
        let modules = import.meta.glob('../views/*/*.vue')

        store.menuList.forEach((element,index1)=>{
                route.children.push({
                    path:element.menuUrl,
                    name:element.menuName,
                    redirect:element.children[0].menuUrl,
                    // component:()=>import(/* @vite-ignore */`../views${element.menuUrl}/index.vue`),
                    component:modules["../views"+element.menuUrl+"/index.vue"],
                    // component:defineAsyncComponent(()=>import(/* @vite-ignore */`../views${element.menuUrl}/index`)),

                    children:[]
                })
                if(element.children.length>0){
                    route.children[index1].redirect = element.children[0].menuUrl;
                    route.children[index1].children=(element.children.reduce((value,item,index)=>{
                        value.push({
                            path:item.menuUrl,
                            // path:item.menuUrl,
                            name:item.menuUrl,
                            component:modules["../views"+item.menuUrl+".vue"],
                            // component:()=>import(/* @vite-ignore */`../views${item.menuUrl}.vue`),
                            // component:defineAsyncComponent(()=>import(/* @vite-ignore */`../views${item.menuUrl}`)),
                            meta:{
                                title:item.menuName,
                                icon:"el-icon-house"
                            }
                        })
                        return value;
                    },[]))
                }
        })
        //添加动态路由
        router.addRoute(route)
        router.options.routes.push(route);
        //重新执行路由守卫函数
        next({...to,replace:true})
    }else{
        next();
    }
    
});

export default router;

二:刷新之后路由和菜单的保持

我将菜单数组以及是否刷新的标识保存在store中了

main.js  //菜单保持,下面逻辑大家根据自己项目进行更改

watchEffect(()=>{
  //用户刷新页面时保存选择的菜单样式,且只刷新时执行一次
  if(store.selectedMenu!==""&&store.isRefreshMenu){
    const splitArray = store.selectedMenu.split("/");
    const path = '/'+splitArray[1];
    const childPath = path+"/"+splitArray[2];
    if(routes[1].children.length>0){
      const menuKey = routes[1].children.findIndex((element)=>{
        return element.path === path;
      })
      selectedMenu.value = [menuKey]
      if(routes[1].children[menuKey].children.length>0){
        const childMenuKey = routes[1].children[menuKey].children.findIndex((element)=>{
          return element.path === childPath;
        })
        nextTick(()=>{
          leftMenuList.value = routes[1].children[menuKey].children;
        })
        selectedLeftKeys.value = [childMenuKey]
      }
    }
    store.isRefreshMenu = false;

  }
})

大家根据自己的router/route.js文件的内容以及自己项目中菜单的逻辑进行灵活变化。这里只是提供动态路由设置的核心代码以及相关核心思路。

你可能感兴趣的:(vue3,router,vue.js,javascript,前端)