乐趣区

关于vue.js:keepalive处理嵌套深层级的路由方案

Vue 应用 实现多级 缓存,有限档次缓存

应用 <keep-alive> 实现缓存目前有三种办法办法

办法一:

  1. 在路由元信息中增加缓存标识:

    {
     path: 'json',
     name: 'json',
     meta: {
     ...
     keepAlive: true
     ...
     },
     component: () => import('../views/components/json')
    },

    2 . 应用 v -if 判断是否缓存

    <keep-alive>
     <router-view v-if="$route.meta.keepAlive"/>
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive"/>

    这种办法是比拟早版本时应用的办法,过后 <keep-alive> 还没有 include 属性。这个办法尽管不便,然而会带来很多 bug,比方无奈应用 <transition>、缓存了不必要的,用来实现嵌套路由操作的<router-view> 布局组件等。

    然鹅,我有强迫症,不能承受没有动效 (~(00)~)

    因而这里重点讲办法二(正在应用的):

    1. 将路由元信息中蕴含 keepAlive: true 的路由记录下来,并将该路由的 name 属性为保护在应用 vuex 中的一个 keepAliveList: [] 里。

    2. 应用 <keep-alive>include属性,来实现动静的组件缓存。

    先说一下 include 属性,它的值能够是:字符串,正则表达式,数组

    首先咱们须要晓得 keep-alive 能够依据 include 中的值来匹配以后路由对应组件的 name 属性(!!不是路由的 name 哦,是组件的 name),来判断这个路由中的组件是否须要缓存。因而咱们只须要将keepAliveList: [] 里保留的须要缓存的路由组件 name 数组传入 include 即可

    因而应用起来就像这样

    <keep-alive :include="keepAliveList">
     <router-view :key="key"/>
    </keep-alive>
    ​
    <script>
    export default {
     name: 'index',
     data () {
     return {keepAliveList: this.$store.getters.getKeepAliveList,}
     },
     computed: {
     // 获取缓存列表
     getKeepAliveList () {return this.$store.getters.getKeepAliveList},
     key () {return this.$route.path}
     },
     watch: {getKeepAliveList (n, o) {this.keepAliveList = n}
     }
    }
    </script>

    然而:

    如果遇到嵌套的 <router-view> 或者嵌套路由(这是很常见的操作),这个时候前面几层 <router-view> 中的组件缓存会出问题

    比方我有上面的三层构造:

{
     path: '/menu-1',
     name: 'menu-1',
     // 布局文件,用来实现多层嵌套的 组件拜访,对于多层次的路由拜访来说,这是必须的
     component: layout, 
     children: [
     {
     path: 'menu-2',
     name: 'menu-2',
     component: layout,
     children: [
     {
     path: 'menu-3',
     name: 'menu-3',
     meta: {keepAlive: true},
     component: () => import('../views/components/menu-3.vue')
     }
     ]
     }
     ]
    }
    
    文件内容 `layout.vue`
    

<template>
 <router-view/>
</template>
​
<script>
export default {name: 'layout'}
</script>

我想要拜访menu-3,在路由之中可视化能够这么看 (layout 写错了,淦):

咱们能够发现,keep-alive只缓存到第一层,也就是 <layout/> 这个组件,而这个组件只是一个 <router-view/> 组件,这显著不是咱们想要的。

咱们须要把 <layout/> 这个无用的组件从 <keep-alive> <router-view/> <keep-alive/> 之中提出,换句话说是将 <menu-3/> 晋升到 <keep-alive> 能缓存的那一层,像这样

如何解决?

须要把嵌套的 <router-view> 拍平

也就是在路由守卫中增加一个将无用的 layout 布局过打消的办法:

// 为什么应用 afterEach 而不会 beforeEach 看 handleKeepAlive 中的正文
router.afterEach((to, from) => {handleKeepAlive(to)
}
​
/**
 * 递归解决多余的 layout : <router-view>,* 让须要拜访的组件放弃在第一层 index : <router-view> 之下
 * @param to
 */
function handleKeepAlive (to) {if (to.matched && to.matched.length > 2) {for (let i = 0; i < to.matched.length; i++) {const element = to.matched[i]
 // 因为 import()异步懒加载, 第一次获取不到 element.components.default.name , 所以不能再 beforeEach 做, 不然第一次拜访的界面不缓存第二次才会缓存
 // afterEach 就不一样了, 这时候能够获取到 element.components.default.name 了
 if (element.components.default.name === 'layout') {to.matched.splice(i, 1)
 handleKeepAlive(to)
 }
 }
 }
}

没有进行 layout 移除时

layout 移除之后

办法三

就是每一层的 router-view 都包裹一层 keep-alive 就好了

退出移动版