You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从API获取的Vue Router动态路由未显示,路径无法访问

Vue Router动态路由添加后不生效问题

我在通过API获取数据创建Vue Router动态路由时遇到了问题:添加的路由没有在router中显示,/examplegrid路径无法访问。我已经调用了router.addRoute方法,但检查router时,从API获取的路由数据并未存在。

相关代码

//router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import axiosInstance from '@/interceptors/axios.js';
import { api } from '@/api';
import Layout from '@/layout';
import Login from '@/login';
import store from '@/store';

const router = createRouter({
    history: createWebHistory(),
    routes: [
        {
            path: '/',
            component: Layout,
            children: [
                {
                    path: '',
                    component: () => import('@/views/Dashboard'),
                    meta: { requiresAuth: true, title: 'Dashboard' }
                }
            ]
        },
        {
            path: '/login',
            component: Login
        },
        {
            path: '/:catchAll(.*)',
            component: () => {
                window.location.href = '/pages/notfound.html';
            },
        },
    ],
});

async function createDynamicRoutes(userStamp, subsidiary, shouldCreateRoutes = true) {
    if (!shouldCreateRoutes) {
          return;
    }

    try {
        const response = await axiosInstance.post(
            api.dynamicRoutes.url,
            {
                UserStamp: userStamp,
                Subsidiary: subsidiary
            },
            {
                headers: {
                    'Content-Type': 'application/json',
                },
            }
        );
   
        const data = response.data.menuPrivileges;

        if (!data) {
            return;
        }

        data.forEach(menuItem => {
            router.addRoute({
                path: menuItem.path,
                component: Layout,
                children: [
                    {
                        path: '',
                        component: () => import('@/views' + menuItem.component),
                        meta: { requiresAuth: true, title: menuItem.menuName }
                    }
                ]
            });
        });

        console.log(JSON.stringify(router.options.routes));
    } catch (error) {
        console.error('Error fetching dynamic routes:', error);
    }
}

createDynamicRoutes('ABC', 'XYZ');

router.beforeEach((to, from, next) => {
    const isAuthenticated = store.state.isAuthenticated;

    if (to.matched.some(record => record.meta.requiresAuth)) {
        if (!isAuthenticated) {
            next({ path: '/login' });
        } else {
            next();
        }
    } else {
        next();
    }
});

export default router;

API响应数据

{
"menuPrivileges":[
    {
    "menuName":"Example Entry",
    "status":"A",
    "component":"/Grid",
    "path":"/ExampleGrid"
    }
]
}

问题排查与解决

1. 别用router.options.routes查看动态路由

router.options.routes是初始化时的静态路由数组,动态添加的路由不会更新到这里,你用它打印看不到动态路由是正常的。要查看所有路由(包括动态添加的),改用console.log(router.getRoutes())。

2. 异步执行时机导致路由未及时加载

createDynamicRoutes是异步函数,直接调用后会继续执行后续代码,但路由添加要等API请求完成后才会执行。这会导致:

  • 首次访问动态路由时,路由还没添加完成,被catchAll通配符路由捕获跳转到404;
  • 路由守卫可能在动态路由添加前就执行,无法正确匹配权限。

解决方式:在应用初始化时先获取动态路由,再创建router。修改main.js如下:

// main.js
import { createApp } from 'vue'
import App from './App.vue'
import { createRouter, createWebHistory } from 'vue-router';
import axiosInstance from '@/interceptors/axios.js';
import { api } from '@/api';
import Layout from '@/layout';
import Login from '@/login';
import store from '@/store';

async function initApp() {
  let dynamicRoutes = [];
  try {
    // 先请求动态路由数据
    const response = await axiosInstance.post(
      api.dynamicRoutes.url,
      { UserStamp: 'ABC', Subsidiary: 'XYZ' },
      { headers: { 'Content-Type': 'application/json' } }
    );
    const data = response.data.menuPrivileges;
    if (data) {
      // 转换为路由格式
      dynamicRoutes = data.map(menuItem => ({
        path: menuItem.path,
        component: Layout,
        children: [
          {
            path: '',
            component: () => import('@/views' + menuItem.component),
            meta: { requiresAuth: true, title: menuItem.menuName }
          }
        ]
      }));
    }
  } catch (error) {
    console.error('获取动态路由失败:', error);
  }

  // 创建router时合并静态路由和动态路由,注意把catchAll放最后
  const router = createRouter({
    history: createWebHistory(),
    routes: [
      {
        path: '/',
        component: Layout,
        children: [
          { path: '', component: () => import('@/views/Dashboard'), meta: { requiresAuth: true, title: 'Dashboard' } }
        ]
      },
      { path: '/login', component: Login },
      ...dynamicRoutes, // 动态路由放在catchAll前面
      {
        path: '/:catchAll(.*)',
        component: () => { window.location.href = '/pages/notfound.html'; }
      }
    ]
  });

  // 路由守卫逻辑不变
  router.beforeEach((to, from, next) => {
    const isAuthenticated = store.state.isAuthenticated;
    if (to.matched.some(record => record.meta.requiresAuth)) {
      isAuthenticated ? next() : next({ path: '/login' });
    } else {
      next();
    }
  });

  createApp(App).use(router).use(store).mount('#app');
}

initApp();

3. 路由顺序问题

通配符路由/:catchAll(.*)会匹配所有未被前面路由匹配的路径,如果动态路由是在它之后添加的,访问动态路由时会先被它捕获。所以必须确保动态路由在通配符路由之前。

4. 路径大小写问题

API返回的路由路径是/ExampleGrid,而你访问的是/examplegrid,Vue Router默认区分大小写。解决方法二选一:

  • 统一访问路径和路由路径的大小写;
  • 在创建router时设置strict: false忽略大小写:
const router = createRouter({
  history: createWebHistory(),
  routes: [...],
  strict: false
});

5. 组件路径检查

确认@/views/Grid组件存在,动态导入路径@/views/+/Grid会变成@/views//Grid,虽然大多数打包工具会自动处理,但最好让API返回的component去掉开头的斜杠,或者在代码中处理:component: () => import('@/views' + menuItem.component.replace(/^\/+/, ''))。

内容的提问来源于stack exchange,提问作者Noob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 18:07:42