本文主要针对的是litemall后端,vue-element-admin只需稍作修改应该也可以适用。路由扁平的思路主要来源于https://blog.csdn.net/weixin_40119256/article/details/111475571,另外解决面包屑显示问题,此文章作记录以供有需要的同行参考。
keep-alive 用于缓存不活跃的组件实例,避免重复渲染和重新创建组件实例。然而,keep-alive 只能缓存其内部的最外层组件,对于嵌套的子组件,keep-alive 无法直接缓存。vue router的第一层是Layout component,如果二级路由是页面则keep-alive自然可以缓存。但是如果嵌套路由超过了两级,则必然会在页面上层至少套上了一层以上的component,keep-alive无法直接缓存,这就是本文要解决的问题。
把路由变成二级的扁平化
- 更新文件./src/store/modules/permission.js
添加获取扁平化路由表的方法。跟参考文章不一样的地方是,我这里的path只需保留最后的两级。不然无法跟litemall的页面路由匹配。如原来path是/A/B/C,这里会变成/B/C。
另外修复源代码的bug,castToFlatRoute(item.children, ’‘)修改为castToFlatRoute(item.children, item.path)。如果存在一个二级菜单,生成的path会缺失父级的path。
/** * 生成扁平化机构路由(仅两级结构) * @param {允许访问的路由Tree} accessRoutes * 路由基本机构: * { * name: String, * path: String, * component: Component, * redirect: String, * children: [ * ] * } */ function generateFlatRoutes(accessRoutes) { const flatRoutes = []for (const item of accessRoutes) { let childrenFflatRoutes = [] if (item.children && item.children.length > 0) { childrenFflatRoutes = castToFlatRoute(item.children, item.path) }
// 一级路由是布局路由,需要处理的只是其子路由数据 flatRoutes.push({ name: item.name, path: item.path, component: item.component, redirect: item.redirect, meta: item.meta, children: childrenFflatRoutes }) }
return flatRoutes }
/** * 将子路由转换为扁平化路由数组(仅一级) * @param {待转换的子路由数组} routes * @param {父级路由路径} parentPath */ function castToFlatRoute(routes, parentPath, flatRoutes = []) { for (const item of routes) { if (item.name === 'approval-management') { debugger } // remove the '/' if item start with '/' let newPath = parentPath + '/' + item.path if (item.path.substring(0, 1) === '/') { newPath = parentPath + item.path } // keep that last 2 parts only const pathParts = newPath.split('/') if (pathParts.length > 3) { newPath = '/' + pathParts[pathParts.length - 2] + '/' + pathParts[pathParts.length - 1] }
if (item.children && item.children.length > 0) { if (item.redirect && item.redirect !== 'noredirect') { flatRoutes.push({ name: item.name, path: newPath, redirect: item.redirect, meta: item.meta }) } castToFlatRoute(item.children, newPath, flatRoutes) } else { flatRoutes.push({ name: item.name, path: newPath, component: item.component, meta: item.meta }) } }
return flatRoutes }
更新GenerateRoutes()方法返回扁平后的路由表。注意不要动原有的这句”commit('SET_ROUTERS', accessedRouters)“。
const flatRoutes = generateFlatRoutes(accessedRouters) resolve(flatRoutes)
更新Router
- 更新文件./src/permission.js
用router.addRoutes(flatRoutes)替换router.addRoutes(store.getters.addRouters)。
store .dispatch('GetUserInfo', getUserToken()) .then(res => { // 拉取user_info const perms = store.getters.perms // note: perms must be a array! such as: ['GET /aaa','POST /bbb'] store .dispatch('GenerateRoutes', { perms }) .then((flatRoutes) => { // flat routes to fix the issue of keep alive cannot cache nested component router.addRoutes(flatRoutes) // 根据perms权限生成可访问的路由表 // router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表 next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record }) }) .catch(err => { store.dispatch('FedLogOut').then(() => { Message.error(err || 'Verification failed, please login again') next({ path: '/' }) }) })
解决面包屑显示问题
- 更新文件./src/store/modules/permission.js
在原有的route上添加matched信息。
/** * add matched for breadcrumb display * @param routes routes list * @returns routers */ function addBreadcrumb(routes, matched = []) { const res = [] routes.forEach(route => { const tmp = { ...route } const tmpMatched = [ ...matched ] tmpMatched.push({ meta: (tmp.meta ? tmp.meta : undefined), redirect: tmp.redirect, path: (tmp.path ? tmp.path : '/') }) if (tmp.children) { tmp.children = addBreadcrumb(tmp.children, tmpMatched) if (tmp.children && tmp.children.length > 0) { tmp.matched = tmpMatched res.push(tmp) } } else { tmp.matched = tmpMatched res.push(tmp) } }) return res }
更新GenerateRoutes()方法在保存之前添加matched信息。
if (perms.includes('*')) { accessedRouters = addBreadcrumb(asyncRouterMap) } else { accessedRouters = addBreadcrumb(filterAsyncRouter(asyncRouterMap, perms)) }
- 更新文件./src/components/Breadcrumb/index
添加getMatchRoute()用于查找匹配的路由。
getMatchRoute(routers, targetName) { for (let k = 0; k < routers.length; k++) { const route = routers[k] if (route.children && route.children.length > 0) { const matched = this.getMatchRoute(route.children, targetName) if (matched !== undefined) { return matched } } else if (route.name === targetName) { return route } } },
添加属性fullRoute用于保存包含面包屑信息的匹配的路由条目。更新getBreadcrumb()根据匹配的路由生成面包屑。
getBreadcrumb() { this.fullRoute = this.getMatchRoute(store.getters.addRouters, this.$route.name) if (!this.fullRoute) { this.fullRoute = this.$route } // only show routes with meta.title let matched = this.fullRoute.matched.filter( item => item.meta && item.meta.title ) const first = matched[0] if (!this.isDashboard(first)) { matched = [{ path: '/home', meta: { title: 'Home' }}].concat(matched) } this.levelList = matched.filter( item => item.meta && item.meta.title && item.meta.breadcrumb !== false ) },
更新pathCompile(),生成链接。
pathCompile(path) { // To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561 const { params } = this.fullRoute var toPath = pathToRegexp.compile(path) return toPath(params) },
注意:如果要启用页面缓存,必须保证路由的name跟component的name一模一样。
参考:
https://blog.csdn.net/weixin_40119256/article/details/111475571
转载请注明出处:https://www.cnblogs.com/keitsi/p/17969846
标签:vue,admin,element,item,meta,path,children,路由,matched From: https://www.cnblogs.com/keitsi/p/17969846