vue-router 多层嵌套时 keep-alive 的问题和解决

6,313 阅读2分钟

需求

前端路由是根据后端返回的菜单设置,自动生成的,理论是不限嵌套层级的。

比如生成一个如下菜单和路由:

首页 - url: '/'
管理员区域
    用户管理
        用户列表 - url: '/users'
        添加用户 - url: '/users/create'

管理员区域用户管理 这两个只用于过渡。我在项目中,这种过渡的路由采用 path: '/' + randomChars(),组件使用 <template><router-view/></template>,并跳转到第一个子组件。

用户列表太多数据,所以我想缓存起来,用 <keep-alive>

问题

代码见:jsfiddle.net/g7L2px8y/

在来回切换 用户列表添加用户 时,用户列表 可以正常缓存,不会弹出 alert。

但是切换到首页后,再点 用户列表,就会弹 alert。因为切换到首页后,Users 的父组件 ParentView 都被销毁了,所以 Users 不可能缓存了。

首先想到的就是,把 ParentView 也缓存起来(codepen 中的 include 变量),但是这样有个更严重的问题。可以尝试如下顺序点击:首页 - 用户列表 - 添加用户 - 首页 - 用户列表,渲染出来的居然是 添加用户。我不知道这是为啥,毕竟我只是个搞 PHP 的,,,

而且把过渡组件缓存起来,还有个问题,那就是当切换到其他分支时,过渡组件下的所有子组件,都会被缓存,浪费啊,,,

解决

在 element admin 的一个 issue 中,有人提出不缓存过渡组件,也能正常缓存的方案,就是路由全部放同一级,不再嵌套。但是就无法使用 this.$route.matches 来做点啥了,,,

看了下 keep-alive 的源码,简单来说,就是把通过 include 匹配的组件的 vnode,放到 keep-alive 组件的一个 cache 对象中,下次渲染时,如果能在这里面找到,就直接渲染(在 render 函数中 return)这个 vnode。

所以我想到,,,改造一下这个 keep-alive 组件,并把这个 cache 对象,放到全局去(全局变量或者 vuex),这样我就可以不用缓存 ParnetView 也能缓存其指定的子组件了。

代码见:jsfiddle.net/axgyzkjn/3/