Subscribe on changes!

`keep-alive`支持自定义缓存key和删除缓存方法

avatar
Jul 3rd 2022

What problem does this feature solve?

Make it easier to control keep-alive caches..

What does the proposed API look like?

  1. KeepAliveInstance.getKeys() => string[] to get all the cached keys.
  2. KeepAliveInstance.removeCache( key: string ) => void to remove a cache.
  3. KeepAliveInstance.clearCaches() => void to remove whole caches.
  4. KeepAliveInstance.switchKey( oldKey: string, newKey: string ) => void to switch the key of a cache to anthor one.
<template>
  <router-view  v-slot="{ Component, route }">
    <transition>
      <keep-alive ref="ka">
        <!-- route.fullPath as the Root VNode Key  -->
        <component :is="Component" :key="route.fullPath" />
      </keep-alive>
     </transition>
  </router>
</template>

<script>
export default {
  methods: {
    removeCache() {
      const keys = this.$refs.ka.getKeys();
      const key = this.$route.fullPath;
      if(keys.includes(key)) {
        this.$refs.ka.removeCache(key);
      }
    },
    clearCaches() {
       this.$refs.ka.clearCaches();
    }
  }
}
</script>
avatar
Jul 5th 2022

有官方大佬回复个吗?这个确实是有很大用处的提议。

keep-alive 可选地把 slots.default() 的 key 用作 root VNode 的 cache key

<keep-alive ref="ka">
  <component :is="Component" :key="route.fullPath" />
</keep-alive>

keep-alive 的内部有 pruneCacheEntry( key: CacheKey ) => void 方法,这个方法可以expose出来,我们用这个方法可以可控地移除缓存。

avatar
Jul 9th 2022

see #4339

看来我只能砍需求了 !- -

avatar
Jul 14th 2022

俺也需要

avatar
Jul 16th 2022

include 其实就可以实现了,把组件包裹一层自定义一下的 name 就可以了。 参考: https://github.com/hminghe/md-admin-element-plus/blob/main/src/components/multi-window/components/MultiWindowKeepAlive.vue

不过还有一点点BUG, 等这个合并了就完美了。https://github.com/vuejs/core/pull/6235

avatar
Jul 16th 2022

include 其实就可以实现了,把组件包裹一层自定义一下的 name 就可以了。 参考: https://github.com/hminghe/md-admin-element-plus/blob/main/src/components/multi-window/components/MultiWindowKeepAlive.vue

不过还有一点点BUG, 等这个合并了就完美了。#6235

给个赞,你的这个方式能解决我的问题!!!感谢大佬的思路!

// 代码大概会是这样子

import { h } from 'vue'

export function wrapperComponent(fullPath: String, comp: VNode) {
  const wraper = {
    name:  fullPath,
    render() {
       return this.$slots.defaunt();
    }
  }
  return h(wraper, null, comp)
}
avatar
Jul 21st 2022

不行啊 调用parentComp.ctx.deacti 报错

avatar
Jul 21st 2022

不行啊 调用parentComp.ctx.deacti 报错

我上传了一个示例代码,你可以看一下, 给 keep-alive 下的 component 接收的组件包上一层自定义 name 的壳

avatar
Jul 25th 2022

不行啊 调用parentComp.ctx.deacti 报错

我上传了一个示例代码,你可以看一下, 给 keep-alive 下的 component 接收的组件包上一层自定义 name 的壳

deactive的时候 还是有问题的 vue-router

hminghe commented 9 days ago 不过还有一点点BUG, 等这个合并了就完美了。https://github.com/vuejs/core/pull/6235

等这个合并

avatar
Jul 25th 2022

我自己项目上用没出现问题。 你这边是有报错还是警告吗?贴一下看看。

avatar
Feb 13th 2023

#7702

My idea can solve this problem, and it has been used in production. But the harm is great. Welcome to discuss and propose better solutions

avatar
Feb 17th 2023
const wraper = {
    name:  fullPath,
    render() {
       return this.$slots.defaunt();
    }
  }

这种自定义组件名称的用法哪里有介绍?没见过这种语法

avatar
Mar 31st 2023

我这么做会有什么不好的地方吗?

        <!-- 路由匹配到的组件将渲染在这里 -->
        <router-view v-slot="{ Component }">
          <keep-alive :include="includeTest">
            <component :is="wrap(Component, $route.fullPath)" />
          </keep-alive>
        </router-view>
const includeTest = ref(['/test/page1'])
onMounted(() => {
  console.log('layout/index onMounted')
})
onActivated(() => {
  console.log('layout/index onActivated')
})
onDeactivated(() => {

})
const cache = new Map()
/**
 * 组件复用缓存处理
 * @param cmp 组件
 * @param fullPath 全路径
 */
const wrap = (cmp: any, fullPath: string) => {
  // console.log('cmp.type:', cmp.type, Object.keys(cmp.type))
  // if (!chchedRoute.value.includes(fullPath)) return cmp
  if (cache.has(fullPath)) {
    cmp.type = cache.get(fullPath)
  }
  else {
    const t: Record<string, any> = {}
    for (const key of Object.keys(cmp.type))
      t[key] = cmp.type[key]
    cmp.type = t
    cmp.type.__name = fullPath
    cache.set(fullPath, cmp.type)
  }
  return cmp
}
avatar
Apr 3rd 2023

@msojocs 抱歉这个我不是很清楚,我只是用vue有提供的api来包个壳,没有使用过这种方式。 你用的这个方式,如果vue组件内部的构成变更了,可能就不能正常使用了。

avatar
Apr 3rd 2023

@msojocs 抱歉这个我不是很清楚,我只是用vue有提供的api来包个壳,没有使用过这种方式。 你用的这个方式,如果vue组件内部的构成变更了,可能就不能正常使用了。

感谢,确实发生发一些问题。(scoped css 出现了问题。。)

编辑: 用 Object.keys(component) 暂时解决了

avatar
Apr 12th 2023

include 其实就可以实现了,把组件包裹一层自定义一下的 name 就可以了。 参考: https://github.com/hminghe/md-admin-element-plus/blob/main/src/components/multi-window/components/MultiWindowKeepAlive.vue 不过还有一点点BUG, 等这个合并了就完美了。#6235

给个赞,你的这个方式能解决我的问题!!!感谢大佬的思路!

// 代码大概会是这样子

import { h } from 'vue'

export function wrapperComponent(fullPath: String, comp: VNode) {
  const wraper = {
    name:  fullPath,
    render() {
       return this.$slots.defaunt();
    }
  }
  return h(wraper, null, comp)
}

这个实践有个问题,包裹进来的组件变成了路由本身,导致层级很深,切换很慢,不知道是哪里的问题 图片

avatar
Apr 12th 2023

include 其实就可以实现了,把组件包裹一层自定义一下的 name 就可以了。 参考: https://github.com/hminghe/md-admin-element-plus/blob/main/src/components/multi-window/components/MultiWindowKeepAlive.vue 不过还有一点点BUG, 等这个合并了就完美了。#6235

给个赞,你的这个方式能解决我的问题!!!感谢大佬的思路!

// 代码大概会是这样子

import { h } from 'vue'

export function wrapperComponent(fullPath: String, comp: VNode) {
  const wraper = {
    name:  fullPath,
    render() {
       return this.$slots.defaunt();
    }
  }
  return h(wraper, null, comp)
}

这个实践有个问题,包裹进来的组件变成了路由本身,导致层级很深,切换很慢,不知道是哪里的问题 图片

devtools 比较卡,关了 devtoools 或者生产环境是不会慢的。