vue-element-admin/litemall后端,超过两级嵌套路由无法缓存的问题
本文主要针对的是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第一个字符是'/',则path从当前开始。如当前条目的path是/me,即使父的path是/parent,当前的path会变成/me。
另外修复源代码的bug,castToFlatRoute(item.children, ’‘)修改为castToFlatRoute(item.children, item.path)。如果存在一个二级菜单,生成的path会缺失父级的path。同时加上props的传递,不然原来通过props传递的参数丢失。
更新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