首页 > 解决方案 > 如何让 Vue.js 组件在路由器更改之间被回收/保留?

问题描述

我正在使用 Vue.js 2.5.x 和 Nuxt 1.4。我相信这是一个与 vue-router 相关的问题。

我在两个不同的 Nuxt 页面上有相同的组件,我想在页面之间导航时保​​留在布局中(不仅仅是在内存中)。

从生命周期事件的角度来看,一些组件从布局中添加和删除,并触发创建、安装然后卸载、销毁的整个生命周期。我了解 keep-alive 是如何工作的,以避免为我们希望在布局中重新安装的组件创建/销毁该过程的开销,这不是这里的问题。

相比之下,当路由改变时,简单的组件似乎根本没有被卸载,好像 Vue 以某种方式理解这些组件在两种不同的布局中看起来是一样的,所以它不仅不会破坏/创建它们......它会让它们留在布局,甚至不卸载它们。

我试图更好地了解在路由之间导航时允许当前页面的组件保持挂载的条件。我发现的许多讨论都是“为什么我的组件不刷新?”的性质。当发生路由更改时,但实际上我遇到了相反的问题:我想保留一个组件及其状态,但该组件正在被破坏。我已经将'key'明确设置为特定的共享值(通常给出相反的建议以确保组件确实卸载)但似乎有比这更深的东西。

同样,为了清楚起见,我不是指“保持活动”,试图挂在内存中暂时从布局中删除的组件上。我在这里观察并试图理解的似乎是一种不同的行为,其中 Vue 的某些部分将组件识别为两个布局之间的相同,并优化了这些组件的销毁和(重新)创建。这是一个巨大的优化,但它的行为似乎没有在我能找到的任何地方讨论或记录。

我有一个 Nuxt 布局,概念上是这样的……</p>

默认.vue:

<template>
  <div>
    <my-marvelous-header-component />
    <nuxt/>
    <my-also-marvelous-footer-component />
  </div>
</template>

…我有几个像这样的 Nuxt 页面…</p>

页面-a.vue:

<template>
  <section id=mainContent>
    <wonderful-component id="wonder1" :key=321 />
    <complex-component-with-children :key=123 />
  </section>
</template>

页面-b.vue:

<template>
  <section id=mainContent>
    <wonderful-component id="wonder1" :key=321 />
    <complex-component-with-children :key=123 />
  </section>
</template>

您会注意到两个页面具有完全相同的组件,并且我尝试使用关键属性来唯一地标识它们,以便与 Vue 沟通这些在渲染时是相同的生物。

当我使用 this.$router.push() 在这些页面之间导航时,我的页眉和页脚组件不受干扰地在路由导航中幸存下来(我通过在生命周期挂钩中放置一些控制台输出来验证这一点),但是美妙和复杂的组件都被破坏了并且然后重新创建。

我试图回收的两个组件内部都有许多动态创建的子组件,因此 vdom 的状态将与初始页面的原始启动条件有很大不同。像美妙或复杂这样的组件没有任何属性或从模板传递的任何其他数据……它们与上面的布局完全一样。我已经尝试为它们提供一个在模板之间共享的唯一 ID 或键值(以及什么都没有),但无论我尝试了什么,路由器推送都会导致这些组件破坏并重新渲染。

像我的页眉和页脚这样的琐碎组件可以很好地回收,我只是想让我的更复杂的组件也表现得一样。

所以我的核心问题是,什么允许或阻止组件的回收?检查什么以确定组件是否可以回收?有没有办法表明组件应该在路由更改之间保留/回收?如果不是,我必须在组件之外保留什么才能使其看起来像在过渡期间坚持的候选者?

我曾认为“key”属性是这里的魔法,但这似乎不起作用,不幸的是浏览 Vue.js 源代码中的这个词发现它被广泛用于命名参数和局部变量......我相信有Vue 中有一个名为“patch()”的函数,它处理至少与新旧组件一致的 vdom 更新,但坦率地说,其中的逻辑超出了我目前的 Vue 知识。如果对 Vue 内部有一些了解的人对代码的哪些部分可能有助于澄清我的想法有见解,我会热衷于再次深入了解这一点。

我觉得我这几天一直在追我的尾巴。非常感谢任何想法或见解。

标签: vue.jsvue-routernuxt.js

解决方案


(不确定这些解释是否足以满足您的需求,但无论如何我都会尝试回答)

Vue 中使用的通用术语不是回收,而是称为keep-alive。这是您在研究时想要使用的术语。

对于 Nuxt,keep-alive 似乎还不可靠。我建议您将所有数据保留在 Vuex 中,并根据 Vuex 中的数据呈现您的元素。

什么允许或阻止组件的回收?检查什么以确定组件是否可以回收?

在这里考虑安装和卸载是很有用的。默认情况下,组件在卸载时总是被销毁。(除非keep-alive被使用。)

在这个例子中,

<my-marvelous-header-component />
<nuxt/>
<my-also-marvelous-footer-component />

<nuxt/><router-view></router-view>Vue 路由器所在的位置。在路由更改时,只有内部的组件router-view会被挂载/卸载。因此,在路由更改时,<my-marvelous-header-component /><my-also-marvelous-footer-component />保持不变并且不会安装/卸载。

有没有办法表明组件应该在路由更改之间保留/回收?

在一个典型的(不是 Nuxt)Vue 项目中,它是通过应用来控制<keep-alive><router-view>

这是一个很好的例子:https ://jsfiddle.net/Linusborg/L613xva0/4/

<div id="app">
  ...
  <keep-alive include="foo">
    <router-view></router-view>
  </keep-alive>
</div>

但是在 Nuxt 中,<router-view>它是自动生成的,您将无法<keep-alive>像在普通的 Vue 项目中那样应用它。

(再次)对于 Nuxt,keep-alive 似乎还不可靠。我建议您将所有数据保留在 Vuex 中,并根据 Vuex 中的数据呈现您的元素。


推荐阅读