Vue

记一次keepAlive踩坑之旅

2019-06-20  本文已影响0人  sphenginx

缘起

现有个vue项目, 某些页面需要缓存。 于是加了 keep-alive, 需要缓存的 router 放在 keep-alive 标签内。
标签如下:

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

后来增加了需求, 某些页面进入 A 的时候需要缓存, 某些页面进入 A 页面的时候需要重新render页面。

这时候需要 watch $route 的 from 和 to , 附实现代码如下:

watch: {
            '$route'(to, from) {
                const reInitList = ['trade', 'ha', 'deal'];
                if(reInitList.includes(from.name) && this.$route.name == 'xxx') {
                    this.init();
                }
            }
}

后来发现,在需要 re init 页面的时候,发现参数读的是之前缓存的参数,并不是当前页面的参数信息。

后来在 vue 的 issue发现大家都有这样的痛点:

https://github.com/vuejs/vue/issues/6509

性空

后来查询 keep-alive 源码发现 render 的时候 有个 key,如果为空就会读取 cid:

render () {
    const slot = this.$slots.default
    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
      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 {
        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])
  }
}

于是考虑 可以把 参数信息当做key的一部分来管理,这样就不会有参数被缓存的问题了。那么 keep-alive标签可以这么写:

<keep-alive :max="20">
      <router-view v-if="$route.meta.keepAlive"  :key="$route.fullPath"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>

大功告成。

上一篇下一篇

猜你喜欢

热点阅读