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

Vue动态路由绑定页面刷新报错(Duplicate named routes definition)求助

问题描述

我是一名Java程序员,最近在学习Vue的动态路由绑定功能。一开始能正常导航到各个子路由,没有报错,但在子路由页面刷新时,出现了Duplicate named routes definition错误。

router/index.js

import Vue, { computed } from 'vue'
import VueRouter from 'vue-router'
import store from '../store/index'
import axios from 'axios'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('../views/Home.vue'),
    children: [
      {
        path: '/index',
        name: 'Index',
        component: () => import('../views/Index.vue')
      },
    ]
  },

  {
    path: '/login',
    name: 'Login',
    component: () => import('../views/Login.vue')
  },
]

const router = new VueRouter({
  routes
})


router.beforeEach((to, from, next) => {
  let hasRouter = store.state.menus.hasRouter
  if (!hasRouter) {
    axios.get('/sys/menu/nav').then(
      res => {
        store.commit('setMenuList', res.data.data.menuList)
        store.commit('setPermList', res.data.data.permList)
        res.data.data.menuList.forEach(
          menu => {
            if (menu.children.length > 0) {
              menu.children.forEach(e => {
                // 转成路由                          
                let route = menuToRoute(e)
                if (route) {
                  router.addRoute('Home', route)
                }
              })
            }
          }
        )
        router.addRoute('Home', {
          path: '*',
          name: 'ERROR404',
          component: () => import('../views/error404.vue')
        })
        store.commit('sethasRouter', true)
      }
    )
  }
  next()

})

const menuToRoute = (menu) => {
  if (!menu.component) {
    return null;
  }
  let route = {
    name: menu.name,
    path: menu.path,
    meta: {
      title: menu.title,
      icon: menu.icon
    }
  }
  route.component = () => import(`@/views/${menu.component}`)
  return route
}

export default router 

mock data

Mock.mock('/sys/menu/nav', 'get', () => {
  // 菜单json
  let menuList = [
    {
      id: 1,
      name: 'SysManga',
      title: '系统管理',
      icon: 'el-icon-s-operation',
      path: '/SysManga',
      component: '',
      children: [
        {
          id :2,
          name: 'SysUser',
          title: '用户管理',
          icon: 'el-icon-s-custom',
          path: '/sys/users',
          component: 'sys/User',
          children: []
        },
        {
          id :3,
          name: 'SysRole',
          title: '角色管理',
          icon: 'el-icon-rank',
          path: '/sys/role',
          component: 'sys/Role',
          children: []
        },
        {
          id :4,
          name: 'SysMenu',
          title: '菜单管理',
          icon: 'el-icon-menu',
          path: '/sys/menu',
          component: 'sys/Menu',
          children: []
        }
      ]
    },
    {
      id :5,
      name: 'SysTools',
      title: '系统工具',
      icon: 'el-icon-s-tools',
      path: '/SysTools',
      children: [
        {
          id :6,
          name: 'SysDict',
          title: '数字字典',
          icon: 'el-icon-s-order',
          path: '/sys/dicts',
          component: 'sys/Dicts',
          children: []
        },
      ]
    }]   
  // 权限数据
  let permList =['SysUser', "SysUser:save"]
  result.data = {
        menuList: [],
        permList: []
      }
  result.data.menuList = menuList
  result.data.permList = permList
 return result
})
问题原因与解决方法

问题原因

刷新页面时,beforeEach钩子会重新执行:

  1. axios请求是异步的,钩子末尾的next()会先执行,此时动态路由还未添加完成就跳转页面;
  2. 异步请求完成后,会再次添加相同的动态路由,导致路由命名重复;
  3. 页面刷新后Vuex状态重置,hasRouter变回false,每次刷新都会重复执行路由添加逻辑。

解决方法

1. 修正路由导航逻辑

修改beforeEach钩子,确保动态路由添加完成后再执行导航,避免重复添加:

router.beforeEach((to, from, next) => {
  let hasRouter = store.state.menus.hasRouter
  if (!hasRouter) {
    axios.get('/sys/menu/nav').then(
      res => {
        store.commit('setMenuList', res.data.data.menuList)
        store.commit('setPermList', res.data.data.permList)
        res.data.data.menuList.forEach(
          menu => {
            if (menu.children.length > 0) {
              menu.children.forEach(e => {
                let route = menuToRoute(e)
                if (route) {
                  router.addRoute('Home', route)
                }
              })
            }
          }
        )
        router.addRoute('Home', {
          path: '*',
          name: 'ERROR404',
          component: () => import('../views/error404.vue')
        })
        store.commit('sethasRouter', true)
        // 添加完路由后重新导航,确保路由生效
        next({ ...to, replace: true })
      }
    )
  } else {
    // 已存在路由,正常跳转
    next()
  }
})

2. 可选:持久化Vuex状态

页面刷新后Vuex状态会重置,若想避免每次刷新都重新请求接口,可将hasRouter和菜单数据持久化到localStorage:

  • 在store的mutations中添加持久化逻辑:
mutations: {
  sethasRouter(state, value) {
    state.menus.hasRouter = value
    localStorage.setItem('hasRouter', JSON.stringify(value))
  },
  setMenuList(state, list) {
    state.menus.menuList = list
    localStorage.setItem('menuList', JSON.stringify(list))
  }
}
  • 在store初始化时读取本地存储:
const state = {
  menus: {
    hasRouter: JSON.parse(localStorage.getItem('hasRouter')) || false,
    menuList: JSON.parse(localStorage.getItem('menuList')) || []
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 14:04:54