Vue ^2.6.14如何使用vue-router4或扩展vue-router3实现addRoute动态路由
适用场景
- 项目运行环境为
vue@^2.6.14,全量迁移Vue3成本过高、存在大量兼容报错 - 需要实现
vue-router@4提供的addRoute(parentName, routeConfig)动态添加嵌套路由能力,功能表现与官方动态路由示例一致 - 需要解决
vue-router@3原生动态路由匹配失效、嵌套路由添加后不生效的已知问题
实现步骤
1. 编写vue-router扩展补丁
新建router/extendRouter.js文件,写入以下扩展逻辑:
import VueRouter from 'vue-router' const originAddRoute = VueRouter.prototype.addRoute VueRouter.prototype.addRoute = function (parentOpt, childOpt) { // 兼容单参数添加顶级路由场景 if (arguments.length === 1) { const route = parentOpt if (!route.name) route.name = `__dyn_${Date.now()}_${Math.random().toString(36).slice(2,8)}` this.matcher.addRoutes([route]) this.replace(this.currentRoute.fullPath) return () => this.removeRoute(route.name) } // 双参数添加嵌套子路由场景 const parentName = parentOpt const childRoute = childOpt // 递归查找目标父路由 const findRoute = (list, name) => { for (const item of list) { if (item.name === name) return item if (item.children?.length) { const res = findRoute(item.children, name) if (res) return res } } return null } const parentRoute = findRoute(this.options.routes, parentName) if (!parentRoute) throw new Error(`Named route "${parentName}" does not exist`) // 初始化children数组,去重后追加新路由 if (!Array.isArray(parentRoute.children)) parentRoute.children = [] const existIdx = parentRoute.children.findIndex(i => i.name === childRoute.name) if (existIdx > -1) parentRoute.children.splice(existIdx, 1) parentRoute.children.push(childRoute) // 重置matcher使新配置生效 this.matcher = new VueRouter().matcher this.matcher.addRoutes(this.options.routes) // 无感刷新当前路由匹配状态 const curPath = this.currentRoute.fullPath this.replace('/__tmp_redirect__').finally(() => this.replace(curPath)) // 对齐v4返回值:返回路由移除函数 return () => { const idx = parentRoute.children.findIndex(i => i.name === childRoute.name) if (idx > -1) { parentRoute.children.splice(idx, 1) this.matcher = new VueRouter().matcher this.matcher.addRoutes(this.options.routes) } } } // 补充对齐v4的removeRoute方法 VueRouter.prototype.removeRoute = function (routeName) { const remove = (list) => { for (let i = 0; i < list.length; i++) { if (list[i].name === routeName) return list.splice(i, 1) if (list[i].children?.length && remove(list[i].children)) return true } return false } remove(this.options.routes) this.matcher = new VueRouter().matcher this.matcher.addRoutes(this.options.routes) }
2. 引入扩展补丁
在项目路由入口文件(通常为router/index.js)的最顶部引入补丁,必须在Vue.use(VueRouter)和路由实例初始化之前加载:
// 顶部优先加载扩展 import './extendRouter' import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) // 初始仅配置2条基础路由即可,和示例逻辑一致 const routes = [ { path: '/', name: 'Home', component: () => import('@/views/Home.vue') }, { path: '/parent', name: 'Parent', component: () => import('@/views/Parent.vue') } ] const router = new VueRouter({ mode: 'history', routes }) export default router
3. 业务调用
API写法与vue-router@4完全一致,无需额外适配:
// 动态给名为Parent的父路由添加嵌套子路由 const removeChild = this.$router.addRoute('Parent', { path: 'child', name: 'ParentChild', component: () => import('@/views/ParentChild.vue') }) // 需要移除路由时直接调用返回的函数即可 // removeChild()
效果说明
- 支持任意层级嵌套路由的动态添加,添加后路由立即生效,无需手动刷新页面
- API入参、返回值与
vue-router@4完全对齐,后续如果升级Vue3无需修改业务层路由调用代码 - 修复了
vue-router@3原生动态路由添加后匹配失效、嵌套路由不识别、当前页跳转白屏等已知问题 - 完全兼容v3原生的
addRoutes、push、replace等原有方法,不会影响存量业务逻辑 - 初始路由仅保留2条基础配置即可,动态添加的路由表现与官方示例完全一致
避坑提示
- 不要尝试在Vue2项目中强行安装
vue-router@4,v4源码中直接依赖Vue3的响应式包,运行时会出现大量不可兼容的报错,没有可行的适配方案 - 动态添加路由时建议给路由配置唯一
name字段,扩展会自动做去重处理,避免重复添加同路由导致的匹配优先级异常 - 如果使用hash路由模式,扩展逻辑无需修改,可直接复用
内容的提问来源于stack exchange,提问作者EaBengaluru
相关产品推荐
相关产品推荐

