Vue.js <keep-alive> 模板中的广告位无效

Vue.js <keep-alive> in template for slot not working

我正在使用一个名为 'Stepper' 的组件,它是一个基本组件,在顶部有一些步骤来指导用户完成一个过程。在这个步进器中,我们生成了一个动态数量的插槽,我们传入一个组件来填充该插槽。

Stepper.vue

...
<div v-for="step in steps" :key="step.name">
  <div class="stepper-pane" v-if="step.name === currentItem.name">
    <slot :name="`${step.name}`" />
  </div>
</div>
...

Parent.vue

...
<Stepper :items="steps"
  <template v-for="step in steps" v-slot:[step.name] :key="step.name">
    <keep-alive>
      <component :is="step.component" />
    </keep-alive>
  </template>
</Stepper>
...

<script lang="ts">
...
import Stepper from "@/components/Stepper.vue";
import Component1 from "@/components/Component1.vue";
import Component2 from "@/components/Component2.vue";

export default defineComponent({
  name: "ParentComponent",
  components: {
    Stepper,
    Component1,
    Component2,
  },
  setup() {
    const steps = ref([
      {
        name: "step1",
        label: "Step 1",
        component: "Component1",
      },
      {
        name: "step2",
        label: "Step 2",
        component: "Component2",
      },
    ]);

    return {
      steps,
    }
  }
</script>

总而言之,一切正常。每个步骤的组件显示,步骤递增等等。我们遇到的问题是 <keep-alive> 不工作。每次您在步骤中来回返回时,组件都会重新呈现,我们会看到调用了 onMounted 挂钩。当然,如果需要,我们可以用一些 'saved' 数据预先填充表单,但如果我们能让 <keep-alive> 工作就更好了。我们也尝试将 :include="[COMPONENT_NAMES]" 添加到 <keep-alive>,但无济于事。

编辑:更新了包含更多详细信息的代码片段。

确保您没有在通常禁用 Chaches 的开发环境中对此进行测试。因此,如果您没有缓存引用,keep-alive 将无法工作。

This means that Vue does not have to create a new instance every single time you switch components. **Instead, it just uses the cached reference whenever you come back to it**. Keep-Alive is what VueJS calls an abstract element – meaning that it does not render a DOM element nor does it show up as a component.

您也可以在控制台工具中禁用缓存。

为了确定您可以检查此设置:

#另一个编辑:

我做了更多研究,并为您的 Keep-alive 组件添加了一个密钥

<component :is="step.component" :key="UniqueIdentifier" />

将帮助您 vue-router 了解此组件已更改。

查看其他 SA 答案:vue Keep-alive not working

<keep-alive> 正在缓存动态 component,但是 Stepper.vue 中的 v-if 指令删除了 div.stepper-pane 及其 <slot>(因此在安装新组件之前销毁当前组件)基于 currentItem.name,这会导致您看到的行为。

解决此问题的一种方法是重构 Stepper.vue,将列表呈现移动到默认插槽中。对我来说,这是有道理的,因为 Stepper.vue 一次只渲染一个 step/slot。

<!-- ParentComponent.vue -->
<Stepper :currentItem="currentItem">
  <keep-alive>
    <component :is="currentItem.component" />
  </keep-alive>
</Stepper>
<!-- Stepper.vue -->
<div class="stepper-pane">
  <slot />
</div>

demo