vue 删除Keep-alive缓存

vue删除Keep-alive缓存

keep-alive简单介绍:

  • 我们项目中为了用户有更好的体验/页面性能,大多数地方都会使用到keep-alive,这个是vue提供的组件,它会将它的子组件进行数据缓存/行为缓存。
    大致原理就是当离开当前组件时,组件并不会被销毁,而是保存在内存中,下次再次访问的时候,不会重新创建新的组件实例,直接从内存中通过特定的key取出缓存的组件实例,进行渲染。

问题:
**

  • 最近我们项目提了一个用户体验的需求,希望同一个页面有些场景有缓存,但是有些场景不希望缓存。

**

需求背景:

  • 当用户将标签页关闭之后,再打开时,之前的缓存还存在用户希望当标签页存在,只是切换标签页时,希望有缓存,当用户点击关闭当前标签页时,希望将缓存清除

探究

  • 当时我一开始看到这个需求,就开始找vue的文档,但是发现vue官方文档并没有提供这样的方法,所以就索性看keep-alive源码。下面直接贴出核心设置缓存的源码,一些关键的地方我都写上了注释
export default {
  name: 'keep-alive',
  abstract: true,

  props: {
    include: patternTypes,
    exclude: patternTypes,
    max: [String, Number]
  },

  created () {
    // 初始化缓存列表,用于存储缓存的虚拟dom
    this.cache = Object.create(null)
    // 缓存的虚拟dom的key值列表
    this.keys = []
  },

  destroyed () {
    for (const key in this.cache) {
      pruneCacheEntry(this.cache, key, this.keys)
    }
  },

  mounted () {
    this.$watch('include', val => {
      pruneCache(this, name => matches(val, name))
    })
    this.$watch('exclude', val => {
      pruneCache(this, name => !matches(val, name))
    })
  },

  render () {
    const slot = this.$slots.default
    // 获取keep-alive的第一个子节点(组件),这里要注意是第一个子节点,缓存存的也是这个子节点(组件)
    const vnode: VNode = getFirstComponentChild(slot)
    // 获取第一个子节点(组件)的配置信息
    const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
    if (componentOptions) {
      // check pattern
      const name: ?string = getComponentName(componentOptions)
      const { include, exclude } = this
      if (
        // not included
        (include && (!name || !matches(include, name))) ||
        // excluded
        (exclude && name && matches(exclude, name))
      ) {
        return vnode
      }

      const { cache, keys } = this
      // 这里获取第一个子节点(组件)的key,
      //如果没有key则利用ctro.cid和组件的name以及tag值拼接生成一个
      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
        // 同时更新Key
        remove(keys, key)
        keys.push(key)
      } else {
        // 如果不存在,则直接存入cache
        // 这里关注cache 和keys 
        // 因为我们后续需要操作这两个变量进行缓存删除
        cache[key] = vnode
        keys.push(key)
        // prune oldest entry
        if (this.max && keys.length > parseInt(this.max)) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode)
        }
      }

      vnode.data.keepAlive = true
    }
    return vnode || (slot && slot[0])
  }
}

通过上述源码,我们可以知道缓存都是存在了keep-alive组件内的cache对象内,以及同时保存了一个缓存组件的key值列表。我们只需要将cache内对应的组件缓存虚拟dom删除就可以达到缓存删除的目的了

实现:

/home/list.vue
//在list组件内的 beforeRouteLeave路由守卫里面操作
beforeRouteLeave(to,from,next){
 // 拿到keep-alive的cache
 // 此处我是因为多嵌套了一层 router-view
 // 所以要向上取2层才能访问到keep-alive组件
 const cache = this.$vnode.parent.parent.componentInstance.cache
 // 拿到keep-alive的keys
 const keys = this.$vnode.parent.parent.componentInstance.keys
 // 获取keep-alive第一个子组件的key值
 // 此处我是因为多嵌套了一层 router-view 
 // 所以要多向上取一次才是keep-alive的第一层子组件 router-view
 const key = this.$vnode.parent.key == null
                                ? this.$vnode.parent.componentOptions.Ctor.cid + (this.$vnode.parent.componentOptions.tag ? `::${this.$vnode.parent.componentOptions.tag}` : '')
                                : this.$vnode.parent.key;
 // 我们的业务(判断当前所有打开的标签页是否有当前页面)
 const flag = this.$store.state.tagsView.visitedViews.find(tag => tag.name === "examManagement")
    if(!flag){
      if(keys.length) {
        let index = keys.indexOf(key)
        // 删除存在keep-alive keys列表内的组件key
        if(index > -1) keys.splice(index,1)
      }
      // 删除当前组件的缓存
      delete cache[key]
      this.$destroy(); // 缓存删除了,顺便也让当前组件销毁
    }
    next()
  },

到此就实现了Keep-alive特定场景缓存删除功能
需要注意的点就是:需要访问到keep-alive组件,因为缓存是存在keep-alive组件内的cache对象内,还有就是keep-alive缓存的是第一层子组件。所以实现时要注意组件嵌套关系。

Vuekeep-alive缓存实现是通过在组件的生命周期中定义了三个钩子函数来实现的。这三个钩子函数分别是created、destroyed和mounted。在created钩子函数中,会初始化两个对象,分别是缓存VNode(虚拟DOM)和VNode对应的键集合。在destroyed钩子函数中,会遍历调用pruneCacheEntry函数删除缓存的VNode实例。在mounted钩子函数中,会实监听黑白名单的变动,并根据变动来更新缓存。具体的实现代码可以在keep-alive.js文件中找到。\[1\]\[2\] 如果想要对部分组件进行缓存,可以在组件的模板中使用<keep-alive>标签,并在需要缓存的组件上添加meta属性,值为keepAlive。例如,在app.vue文件中,可以使用<keep-alive>标签包裹需要缓存的组件,并在组件的<router-view>标签上添加v-if="$route.meta.keepAlive"条件判断。这样就可以实现对指定组件的缓存效果。\[3\] #### 引用[.reference_title] - *1* *2* [Vue中利用keep-alive-快速实现页面缓存-案例](https://blog.csdn.net/JackieDYH/article/details/119913544)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [示例vuekeep-alive缓存功能的实现](https://blog.csdn.net/weixin_34029949/article/details/91458411)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值