当前位置: 首页 > 知识库问答 >
问题:

前端 - 这个vue3动态路由访问不了?

李辉
2023-04-27

我想写一个vue3动态路由的demo,写完之后,在浏览器上访问/home或者/system均是白屏,只有/login是可以正常访问的,这段代码到底是哪里出现了问题?

这是我的路由数据:

Mock.mock("/getMenus", "get", {
  status: 200, //请求成功状态码
  menus: [
    {
      path: "/",
      name: "Main",
      component: "MainView",
      redirect: "home",
      children: [
        {
          path: "home",
          name: "home",
          component: "HomeView",
          meta: {
            title: "首页",
            icon: "HomeFilled",
          },
        },
      ],
    },
    {
        path: "/system",
        name: "system",
        component: "SystemView",
        meta: {
          title: "首页",
          icon: "HomeFilled",
        },
      }
  ],
});

这是我的代码:

import { createRouter, createWebHistory } from "vue-router";
import { getMenus } from "../api/getMenu.js";


const routes = [
  {
    path: "/login",
    name: "login",
    component: () => import('../views/LoginView.vue'),
  },

];

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes,
});


function formatRoute(r) {
  if (r.children && r.children.length > 0) {
      let result = {
        path: r.path,
        name: r.name,
        component: () => import(`../views/${r.component}.vue`),
        children: []
      }
      r.children.forEach(item => {
        let child = {
          path: item.path,
          name: item.name,
          component: () => import(`../views/${item.component}.vue`),
          meta: item.meta
        }
        
        result.children.push(child)
      })
      return result
    } else {
      return {
        path: r.path,
        name: r.name,
        component: () => import(`../views/${r.component}.vue`),
      }
    }   

}

function addRoute(data) {
  data.forEach(item => {
    let r = formatRoute(item)
    router.addRoute(r)
  })    
}


router.beforeEach((to, from, next) => {
  loadRoutes()
  next()
});

 function loadRoutes(){
     getMenus().then(res => {
     addRoute(res.data.menus)
     console.log(router.getRoutes())
  });
  
}

export default router;

控制台打印console.log(router.getRoutes())已经看到路由已经添加了进去,但是浏览器访问对应的路由显示空白,报错提示没有匹配的路由,这是哪个地方有问题?

共有1个答案

凤柏
2023-04-27

从你上面的代码来看,你在router.beforeEach钩子函数中调用了loadRoutes(),这样会在每次路由跳转之前去加载路由。但是,因为getMenus()是异步操作,loadRoutes()还没有完成添加路由的操作,就执行了next(),导致在路由跳转之前,新的路由还没有被添加到路由表里,所以会出现你说的空白页面的问题。

你可以在loadRoutes()函数中返回一个Promise,还有在router.beforeEach里等待loadRoutes()函数执行完毕后再调用next()。这些地方改一下:

// 修改 loadRoutes 
function loadRoutes() {
  return new Promise((resolve) => {
    getMenus().then((res) => {
      addRoute(res.data.menus);
      console.log(router.getRoutes());
      resolve();
    });
  });
}

// 修改 router.beforeEach 
router.beforeEach(async (to, from, next) => {
  await loadRoutes();
  next();
});

然后,为了不让每次路由跳转时都去请求路由数据,你可以在loadRoutes函数中判断是否已经加载过路由,如果已经加载过,就不再重新加载:

let isRoutesLoaded = false; // 添加一个标识,初始值为 false

// 修改 loadRoutes 函数
function loadRoutes() {
  return new Promise((resolve) => {
    if (isRoutesLoaded) {
      resolve();
      return;
    }

    getMenus().then((res) => {
      addRoute(res.data.menus);
      console.log(router.getRoutes());
      isRoutesLoaded = true; // 路由加载完成后,将标识设为 true
      resolve();
    });
  });
}

这样只有在第一次访问页面时才会去加载动态路由,之后的路由跳转不会再次加载。

 类似资料:
  • 想通过v-router路由守卫和vuex实现一个动态路由,路由数据由后端返回,求一个demo参考下。

  • 目前是开发环境,history模式,有个index.vue的主页加了路由组件<RouterView/>,在路由导航守卫中向这个页面动态加了子路由,点击菜单的时候,跳转到了对应页面,但刷新后会打到404页面,后面发现是加了这个导致的“path: "/:catchAll(.*)",redirect: '/404',” 如果不加则正常,但是控制台会出现警告[Vue Router warn]: No ma

  • next.js(app router) 在 ssg(output: "export") 模式下 我的动态路由 /app/live/[id]/page.tsx 可以类似 react-router 那样动态获取么 id 么(useParams),而不是用 generateStaticParams 去生成,因为可能会有数万乃至数 10 万个 id

  • 这个所属公司里面我想动态添加几个从接口获取的二级行业并且生成对应的路由点击跳转不同的页面,这个在vue3和vite项目中要怎么实现呢 就比如这种效果 我想的是先通过rouer.option.route获取route,然后再拿到这个所属公司这个route,其次再获取接口拿到接口数据,通过addroute添加进去路由里面,然后我试了下这个方案不太行,而且会重复添加,我也不能设置一个变量去防止他重复添加

  • router.getRoutes()数据如下。 页面报错No match found for location with path "/a" 路由跳转:空白页面。

  • 我有以下Vuex商店(main.js): 我还为Vue路由器(routes.js)定义了以下路由: 我试图这样做,如果Vuex存储了对象,并且将属性设置为,则路由器会将用户重定向到登录页面。 我有这个: 问题是,我不知道如何从函数内部访问Vuex商店的对象。 我知道我可以在组件中使用来设置路由器保护逻辑,但这会使每个组件变得杂乱无章。我想在路由器级别集中定义它。