Vuejs <keep-alive> 有什么意义?

What is the point of Vuejs <keep-alive>?

基本上,就是它所说的。 <keep-alive> 有什么意义?这听起来可能很愚蠢,但我认为目的是缓存与当前未在 DOM 中呈现的组件关联的数据。根据 this bug/issue<keep-alive> 专门 设计用于在从页面中删除元素时删除它持有的缓存。那我错过了什么?

为什么我要将 <keep-alive>v-show 一起使用? v-show 的重点不就是该元素仍然存在于页面上,只是将 CSS 设置为隐藏它吗?默认情况下,元素使用 v-show 隐藏时会丢失数据吗?

需要说明的是,下面的示例显然应该不起作用(根据我链接的已关闭 bug/issue):

<div v-if="lazyLoaded && userClickedToShow">
    <h2>{{someLazyLoadedData.title}}</h2>
    <div id="otherStuff">
        ...
    </div>
    <keep-alive>
        <some-child-component :prop="someLazyLoadedData"></some-child-component>
    </keep-alive>
</div>

所以我预计 <keep-alive> 在这种情况下会缓存与 <some-child-component> 关联的数据,一旦它被加载,并且如果用户点击显示(可能是很多数据出于性能原因,我不想在 DOM 中出现,除非用户专门单击以显示它,或其他)它会切换显示,但会保留搜索词或组件中发生的任何事情。

有没有一种方法可以重写它以符合 <keep-alive> 的预期功能?我是否必须绑定到 <component> 上的 is,如果我现在不想让它呈现,就将其设置为空?是这样的吗?

<keep-alive>
    <component :is="lazyLoaded && userClickedToShow ? 'SomeChildComponent' : ''" :prop="lazyLoaded && someLazyLoadedData"></component>
<keep-alive>

这似乎混淆了那里实际发生的事情,如果它真的有效的话。还假设 SomeChildComponent 的 prop 可以采用 false,但它可能无法采用。我不喜欢那个选项。我想稍微好一点的是将整个东西包装在一个 if 块中,也许?

<div v-if="lazyLoaded">
    <keep-alive>
        <component :is="userClickedToShow ? : 'SomeChildComponent' : ''" :prop="someLazyLoadedData"></component>
    <keep-alive>
</div>

当然,这假设 <keep-alive>v-if 块中起作用,但它可能不会。此外,它仍然不如第一种方式(行不通)那么清晰。我不喜欢将 is 设置为 '' 除非那真的是唯一的方法。当然,这些选项都不允许条件控制更大的块,只有元素保持活动状态。

刚刚花了两天的大部分时间试图弄清楚为什么 <keep-alive> 无法让任何东西保持活力!希望有一些简单的东西我只是想念!

编辑:更新初始示例以更好地反映我的用例。

I thought the purpose was to cache data associated with an component not currently being rendered in the DOM

不,它不缓存组件的数据。它缓存整个组件实例(包括它的整个状态)。简单地说,它使组件实例存活而不是被销毁...

According to this bug, is specifically designed to drop the cache it was holding when an element was removed from the page. So what am I missing?

从这个 "bug" 中得到的要点是 "whenever <keep-alive> component is destroyed (because it is itself inside v-if), it drops all cached components..."

Why would I want to use <keep-alive> with v-show? Isn't the whole point of v-show that the element still exists on the page, just has CSS set to hide it?

是的,这正是 v-show 的要点,将它与 <keep-alive> 一起使用是没有意义的(因为 v-show 不会导致组件成为 destroyed/created )

By default, does an element lose data when it's hidden with v-show?

不,被 v-show 隐藏的组件仍然存在于内存中,在组件树 和 DOM 中并保持其状态....

To be clear, the follow example is apparently supposed to not work (according to the closed bug I linked anyway)

<div v-if="lazyLoaded && userClickedToShow">
    <keep-alive>
         <some-child-component :prop="someLazyLoadedData"></some-child-component>
    </keep-alive>
</div>

...是的,它不起作用,因为:

  1. v-if === false 将销毁 <keep-alive> 组件(如果它之前被渲染过)(但这并不完全正确,因为 <keep-alive> 是 "render-less" 在某种意义上它只是提供功能和不向 DOM 呈现任何东西,除了它的子组件)。
  2. 并且 v-if === true 将创建 <keep-alive> 并呈现它的子组件

为了使其正常工作,您需要将 <keep-alive> 移到 v-if 之外:

<keep-alive>
    <some-child-component v-if="lazyLoaded && userClickedToShow" :prop="someLazyLoadedData" />
</keep-alive>

v-if 条件的结果为 true 时,上述代码应导致 some-child-component 被渲染(并同时放入 <keep-alive> 的缓存中) .当 v-if 切换到 false 时,组件的模板从 DOM 中删除,但组件保留在缓存中而不是被销毁。

在这种情况下,v-if(连同 <keep-alive>)和 v-show 之间的主要区别在于,对于 v-if/keep-alive 组合,组件实例保存在内存中,但它的模板结果不是 DOM 的一部分,而对于 v-show 组件是活动的 相应的 HTML它呈现的是 DOM 的一部分(只是隐藏)

然后回答你的问题....<keep-alive> 主要是为动态组件 (<component :is="" >) 设计的,特别是 Vue-router...

更新(...因为有问题的更新代码)

<div v-if="lazyLoaded && userClickedToShow">
    <h2>{{someLazyLoadedData.title}}</h2>
    <div id="otherStuff">
        ...
    </div>
    <keep-alive>
        <some-child-component :prop="someLazyLoadedData"></some-child-component>
    </keep-alive>
</div>

由于与第一个示例相同的原因,此代码将无法按预期工作 - 如果 keep-alive 被破坏(由于 v-if 条件评估为 false),它将删除所有缓存的组件。 keep-alive 只是本地缓存,只有当它本身是 "rendered".

时才会起作用

Is there a way to rewrite this that would fit with how is supposed to function?

你最好的选择就是将你想要的所有东西 "toggle" 包装到一个组件中,然后像这样使用该组件:

<keep-alive>
  <my-component v-if="lazyLoaded && userClickedToShow" :prop="someLazyLoadedData" />
</keep-alive>

...所有其他变体都会失败,您可以在 this demo

中尝试查看

Docs

Note, <keep-alive> is designed for the case where it has one direct child component that is being toggled. When there are multiple conditional children, <keep-alive> requires that only one child is rendered at a time.

  • 如果它有多个 rendered child
  • ,它将不起作用
  • 如果子组件不是组件(例如<div),它将不起作用