需求

单页面应用中,用户进入表单填写页面,需要初始化表单内容,填写过程中可能涉及到地图选点或者列表选择等操作,需要到新的页面选择并回调显示。

此时我们需要缓存表单填写页面实例,当退出表单填写或提交完表单内容之后,需要销毁当前表单实例,下次进入重新进行初始化

思考

说到 Vue 缓存,我们肯定首先选择官方提供的缓存方案 keep-alive 内置组件来实现。

keep-alive 组件提供给我们缓存组件的能力,可以完整的保存当前组件的状态,这帮了我们很大的忙

但实际业务场景中,我们很多时候是按需缓存页面的,就像 App 开发那样,每个页面都是单独的一个页面实例,由于 Vue Router 的限制,每个页面有固定的一个 path,所以导致每次访问这个 path 都会命中同一个组件实例

这个时候可能会有小伙伴说

诶,不是可以用 activated 来进行页面更新或者处理吗?

没错,是可以这样,但是,有些操作是 mounted 里面要做,有些需要放到 activated 里面更新,代码要处理很多进入页面的操作,就很麻烦啊。

此时就有两个思考方向:

  • 在必要的时候清除掉缓存页面的实例
  • 每次 push 页面的时候,保证当前页面是全新的实例对象,和 App 页面栈相同

第二种方案可以比较物理的解决需求中的问题,但是需要改动的地方很多,比如 Vue Router 中路由切换的时候,是否采用动态生成 path ,确保当前页面实例不唯一,而且我们也要做好自己的页面栈管理,类似于 iOS 中的 UINavigationController ,以便于及时清理栈中缓存的页面实例

因为改动比较大,而且需要大量测试,所以最后还是选择在方案一的方向进行探索和尝试。

尝试

1. 手动操作 keep-alive 组件的 cache 数组

//  Vue 2 keep-alive 部分源码片段
const { cache, keys } = this;
const key: ?string =
    vnode.key == null
        ? // same constructor may get registered as different local components
          // so cid alone is not enough (#3269)
          componentOptions.Ctor.cid   (componentOptions.tag ? `::${componentOptions.tag}` : "")
        : vnode.key;
if (cache[key]) {
    vnode.componentInstance = cache[key].componentInstance;
    // make current key freshest
    remove(keys, key);
    keys.push(key);
} else {
    // delay setting the cache until update
    this.vnodeToCache = vnode;
    this.keyToCache = key;
}

通过路由守卫在特定的情况下删除 cache 数组中的页面实例,同时 destory 当前实例

removeKeepAliveCacheForVueInstance(vueInstance) {
    let key =
        vueInstance.$vnode.key ??
        vueInstance.$vnode.componentOptions.Ctor.cid   (vueInstance.$vnode.componentOptions.tag ? `::${vueInstance.$vnode.componentOptions.tag}` : "");
    let cache = vueInstance.$vnode.parent.componentInstance.cache;
    let keys = vueInstance.$vnode.parent.componentInstance.keys;
    if (cache[key]) {
        vueInstance.$destroy();
        delete cache[key];
        let index = keys.indexOf(key);
        if (index > -1) {
            keys.splice(index, 1);
        }
    }
}

这种方案比较繁琐,但由于是直接操作 cache 数组,可能会产生一些预期外的泄漏问题或者运行问题,虽然我自己尝试的时候没有发现。。

Vue 3 中我也尝试去寻找对应的 cache 数组,还真被我找到了,但是 Vue 3 源码中对于 cache 数组的操作权限仅限于开发环境

// Vue 3 KeepAlive 组件片段
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
    ;(instance as any).__v_cache = cache
}

部署生产环境之后就没办法通过 instance.__v_cache 来获取 cache 数组了,所以这种方案到 Vue 3 就没办法进行下去啦。

于是乎,就有了第二个尝试

2. exclude 大法好

之前接触 keep-alive 所有注意力都放在 include 这个属性上面,其实 exclude 属性同样重要,而且效果和我们直接删除 cache 数组异曲同工。

// Vue 3 KeepAlive 组件片段
 if (
    (include && (!name || !matches(include, name))) ||
    (exclude && name && matches(exclude, name))
    ) {
        current = vnode
        return rawVNode
    }

如果 exclude 里面有值,那么就返回当前新的实例不从 cache 里面获取。而且 exclude 的优先级是高于 include 的。

利用这一点,我们就可以通过操作 exclude 中的内容,来达到控制缓存页面的效果。

而且 excludeVue 3 中的控制更为方便,只需要定义一个全局的 exclude 响应式变量就可以随处操作了,清除的具体方式取决于业务流程

export const excludes = ref<string[]>([]);
// 需要删除的时候
export function removeKeepAliveCache(name: string) {
    excludes.value.push(name);
}
// 需要恢复缓存的时候
export function resetKeepAliveCache(name: string) {
    excludes.value = excludes.value.filter((item) => item !== name);
}

Demo

这里提供一个小 demo 演示一下缓存清除效果:

https://ztstory.github.io/vue-composition-demo/#/

流程:

  • IndexInput 为缓存页面

  • Input 返回到 Index 时清除 Input 缓存,重新进入 Input 页面激活缓存

Demo 源码地址:https://github.com/ZTStory/vue-composition-demo

到此这篇关于详解Vue适时清理keepalive缓存方案的文章就介绍到这了,更多相关Vue清理keepalive缓存内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

详解Vue适时清理keepalive缓存方案的更多相关文章

  1. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  2. 如何在Android中设置keepalive超时?

    看起来我可以这样做,如果我使用NDK,但我想将此代码分发为jar,所以这对我来说并不理想.解决方法这可能是一个非常明显的答案[即它不是你特定案例的选项]但是你当然可以通过每10分钟发送1个丢弃字节来实现你自己的keepalive.

  3. vue自定义加载指令v-loading占位图指令v-showimg

    这篇文章主要为大家介绍了vue自定义加载指令和v-loading占位图指令v-showimg的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. vue使用动画实现滚动表格效果

    这篇文章主要为大家详细介绍了vue使用动画实现滚动表格效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. 关于Vue 监控数组的问题

    这篇文章主要介绍了Vue 监控数组的示例,主要包括Vue 是如何追踪数据发生变化,Vue 如何更新数组以及为什么有些数组的数据变更不能被 Vue 监测到,对vue监控数组知识是面试比较常见的问题,感兴趣的朋友一起看看吧

  6. Vue子组件props从父组件接收数据并存入data

    这篇文章主要介绍了Vue子组件props从父组件接收数据并存入data的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  7. Vue h函数的使用详解

    本文主要介绍了Vue h函数的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  8. VUE响应式原理的实现详解

    这篇文章主要为大家详细介绍了VUE响应式原理的实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

  9. vue+Element ui实现照片墙效果

    这篇文章主要为大家详细介绍了vue+Element ui实现照片墙效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. vue+elemet实现表格手动合并行列

    这篇文章主要为大家详细介绍了vue+elemet实现表格手动合并行列,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部