core icon indicating copy to clipboard operation
core copied to clipboard

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

Open chenhaihong opened this issue 2 years ago • 10 comments

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>

chenhaihong avatar Jul 03 '22 13:07 chenhaihong

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

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出来,我们用这个方法可以可控地移除缓存。

chenhaihong avatar Jul 05 '22 11:07 chenhaihong

see https://github.com/vuejs/core/pull/4339

edison1105 avatar Jul 09 '22 00:07 edison1105

see #4339

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

chenhaihong avatar Jul 09 '22 04:07 chenhaihong

俺也需要

yokiyokiyoki avatar Jul 14 '22 07:07 yokiyokiyoki

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

hminghe avatar Jul 16 '22 07:07 hminghe

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)
}

chenhaihong avatar Jul 16 '22 07:07 chenhaihong

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

zezhongmiao avatar Jul 21 '22 02:07 zezhongmiao

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

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

chenhaihong avatar Jul 21 '22 12:07 chenhaihong

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

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

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

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

等这个合并

zezhongmiao avatar Jul 25 '22 08:07 zezhongmiao

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

chenhaihong avatar Jul 25 '22 08:07 chenhaihong

#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

jiangshengdev avatar Feb 13 '23 10:02 jiangshengdev

const wraper = {
    name:  fullPath,
    render() {
       return this.$slots.defaunt();
    }
  }

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

zhoufanglu avatar Feb 17 '23 08:02 zhoufanglu

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

        <!-- 路由匹配到的组件将渲染在这里 -->
        <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
}

msojocs avatar Mar 31 '23 12:03 msojocs

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

chenhaihong avatar Apr 03 '23 07:04 chenhaihong

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

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

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

msojocs avatar Apr 03 '23 08:04 msojocs

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)
}

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

4color avatar Apr 12 '23 09:04 4color

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 或者生产环境是不会慢的。

hminghe avatar Apr 12 '23 09:04 hminghe