微人事 vue-roter4实现动态加载路由,解决[Vue Roter warn]: No match found for location with path “xxx“
目录
一:解决初次加载子菜单报错 No match found for location with path “xxx”
最近在做微型人事项目,进行到左边导航菜单动态加载部分,前端所有的子项都无法打开
以基本资料为例,点击会在控制台弹出如下警告信息:
教程中src/utils/menus.js
内的initMenu
方法从后台请求得到动态的菜单栏数据data
,使用formatRoutes
方法将data
中的“component”对应的字符串数据转化为.vue
组件。
教程代码:
import {getRequest} from "./api";
export const initMenu = (router, store) => {
if (store.state.routes.length > 0) {
return;
}
getRequest("/system/config/menu").then(data => {
if (data) {
var str1 = JSON.stringify(data)
console.log("data:"+str1)
let fmtRoutes = formatRoutes(data);
console.log("fmtRoutes:"+JSON.stringify(fmtRoutes))
router.addRoutes(fmtRoutes)
console.log("所有:"+JSON.stringify(router.options.routes))
store.commit('initRoutes', fmtRoutes);
}
})
}
export const formatRoutes = (routes) => {
let fmRoutes = [];
routes.forEach(router => {
let {
path,
component,
name,
meta,
iconCls,
children
} = router;
if (children && children instanceof Array) {
children = formatRoutes(children);
}
let fmRouter = {
path: path,
name: name,
iconCls: iconCls,
meta: meta,
children: children,
component(resolve) {
if (component.startsWith("Home")) {
require(['../views/' + component + '.vue'], resolve);
} else if (component.startsWith("Emp")) {
require(['../views/emp/' + component + '.vue'], resolve);
} else if (component.startsWith("Per")) {
require(['../views/per/' + component + '.vue'], resolve);
} else if (component.startsWith("Sal")) {
require(['../views/sal/' + component + '.vue'], resolve);
} else if (component.startsWith("Sta")) {
require(['../views/sta/' + component + '.vue'], resolve);
} else if (component.startsWith("Sys")) {
require(['../views/sys/' + component + '.vue'], resolve);https://next.router.vuejs.org/zh/guide/advanced/dynamic-routing.html
}
}
}
fmRoutes.push(fmRouter);
})
return fmRoutes;
}
①:使用router.addRoute()代替router.addRoutes()
教程中使用的是vue2(vue router3)而我目前的环境是vue3(vue router3),教程中使用router.addRoutes(fmtRoutes)
将处理过的后台数据加到router内,查看router.addRoutes和动态路由可以知道目前router.addRoutes()
已经被router.addRoute()
代替,目前不能一次性添加多条路由规则,而是一次添加一条。
于是计划遍历fmtRoutes
然后用router.addRoute()
挨个存入·。
fmtRoutes.forEach(t => {
router.addRoute(t)
})
但修改完后还是报错,报错信息如下:
②:修改组件引入方式
component(resolve) {...}
这块代码的主要作用是根据不同的component
开头名字引入不同目录下的.vue
文件,怀疑是require
这种引入方式有问题,于是改成import
,最终component(){...}
代码块如下:
component() {
if (component.startsWith("Home")) {
return import('../views/' + component );
} else if (component.startsWith("Emp")) {
return import('../views/emp/' + component);
} else if (component.startsWith("Per")) {
return import('../views/per/' + component);
} else if (component.startsWith("Sal")) {
return import('../views/sal/' + component);
} else if (component.startsWith("Sta")) {
return import('../views/sta/' + component);
} else if (component.startsWith("Sys")) {
return import('../views/sys/' + component);
}
}
测试:
发现员工资料
下的基本资料
不能正常访问(以admin账户登录),其他菜单的子项都能访问。
如:人事管理
下的员工资料
就可以正常访问
查看后端返回的json
[
{
"id": 2,
"url": "/",
"path": "/home",
"component": "Home",
"name": "员工资料",
"iconCls": "fa fa-user-circle-o",
"meta": {
"keepAlive": null,
"requireAuth": true
},
"parentId": 1,
"enabled": true,
"children": [
{
"id": 7,
"url": null,
"path": "/emp/basic",
"component": "EmpBasic",
"name": "基本资料",
"iconCls": null,
"meta": {
"keepAlive": null,
"requireAuth": true
},
"parentId": 2,
"enabled": true,
"children": null
}
]
},...
员工资料
下的基本资料
是存在的,而且component
值为"EmpBasic"
于是把经过处理的后台数据fmtRoutes遍历,输出到控制台。
fmtRoutes.forEach(t => {
console.log("t:"+JSON.stringify(t))
router.addRoute(t)
})
可以看出第一个员工资料
存在子项基本资料
那么问题可能在router.addRoute(t)
这个过程中,用router.getRoutes()
查看router加入数据之后的信息,在控制台输出。
fmtRoutes.forEach(t => {
console.log("t:"+JSON.stringify(t))
router.addRoute(t)
})
console.log(router.getRoutes())
③:修改路由中重复的name值
从上图可知只存在一个name
为员工资料的路由,而且path
为'/per/emp'
,怀疑是router
不允许name
值重复,于是在数据库中将该name
值改成员工信息
。
测试:
访问正常!
二:解决在某一个子菜单页刷新,报错 No match found for location with path “xxx”
当我们解决完第一个问题时,会发现:虽然所有子菜单项目都能正常访问,但是在当前子菜单项点击刷新后,会显示空白页面,控制台继续报错No match found for location with path "xxx"
,以员工资料
下的基本资料
为例:
查看控制台,可以看到Vue Roter在一开始就被调用了,而component
得在之后才能引入,自然就找不到了,参考next({…to, replace: true})的作用,(确保动态路由完全加载)修改代码:
①修改menus.js/initMenu方法
修改前:
export const initMenu = (router, store) => {
if (store.state.routes.length > 0) {
return;
}
getRequest("/system/config/menu").then(data => {
if (data) {
let fmtRoutes = formatRoutes(data);
store.commit('initRoutes',fmtRoutes);
fmtRoutes.forEach(t => {
router.addRoute(t)
})
console.log(router.getRoutes())
}
})
}
修改后:
export const initMenu=(router, store,next)=>{
if(store.state.routes == 0) {
getRequest("/system/config/menu").then(data=>{
if(data) {
let fmtRoutes = formatRoutes(data);
store.commit('initRoutes',fmtRoutes);
fmtRoutes.forEach(t => {
router.addRoute(t)
})
next({...to, replace: true})
console.log(router.getRoutes())
}
})
} else {
next();
}
}
②将menus.js/initMenu方法的实现移动到main.js/router.beforeEach(){…}内部,确保next({…to, replace: true})运行
修改前:
router.beforeEach((to, from,next) => {
if (to.path == '/') {
next();
}else {
if(window.sessionStorage.getItem("user")) {
initMenu(router, store);
next();
} else {
next('/?redirect='+to.path)
}
}
})
修改后:
router.beforeEach((to, from,next) => {
if (to.path == '/') {
next();
}else {
if(window.sessionStorage.getItem("user")) {
if(store.state.routes == 0) {
getRequest("/system/config/menu").then(data=>{
if(data) {
let fmtRoutes = formatRoutes(data);
store.commit('initRoutes',fmtRoutes);
fmtRoutes.forEach(t => {
console.log("t:"+JSON.stringify(t))
router.addRoute(t)
})
next({...to, replace: true})
}
})
} else {
next();
}
} else {
next('/?redirect='+to.path)
}
}
})
测试:刷新正常显示。
前端项目仓库:人事管理(前端)
更多推荐
所有评论(0)