如何在路由器更改之间使Vue.js组件可回收/持久化?

vue.js Vue.js

猴子

2020-03-24

I am using Vue.js 2.5.x and Nuxt 1.4. I believe this is a question related to vue-router.

I have the same component on two different Nuxt pages that I want to preserve in the layout (not just in memory) when navigating between the pages.

To put this in terms of lifecycle events, some components are added and removed from a layout and trigger a whole lifecycle of being created, mounted then unmounted, destroyed. I understand how keep-alive works to avoid the created/destroyed overhead of that process for components we expect to be re-mounted in the layout, and that isn't the question here.

In contrast, simple components seem to not be unmounted at all when a route changes, as though Vue somehow understands that these components will appear the same in two different layouts so not only does it not destroy/create them... it leaves them in the layout and doesn't even unmount them.

I am trying to get a better understanding of the conditions that allow a current page's components to remain mounted when navigating between routes. Many of the discussions I’ve found are of the nature of “Why isn’t my component refreshing?” when a route change happens, but I actually have the opposite problem: I want to preserve a component and its state, but the component is getting destroyed. I have played with setting 'key' explicitly to a specific shared value (the opposite advice usually given to insure components DO unmount) but there seems to be something deeper than this.

Again, for clarity, I'm not referring to "keep-alive" trying to hang onto components in memory that are temporarily removed from a layout. What I am observing and trying to understand here seems to be a different behavior, where some part of Vue recognizes components as being identical between two layouts and it optimizes away the destroy and (re)create of such components. This is a huge optimization, but one whose behavior doesn't seem to be discussed or documented anywhere I can find.

I have a Nuxt layout that is conceptually like this…

default.vue:

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

…and I have a couple of Nuxt pages that look like this…

page-a.vue:

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

page-b.vue:

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

You’ll note that both pages have exactly the same components, and I’ve tried to identify them uniquely with key properties in an effort to communicate to Vue that these are the same creatures at render time.

When I navigate between these pages with this.$router.push(), my header and footer components survive the route navigation unmolested (I verified this by putting some console output in the lifecycle hooks), however both wonderful and complex components are destroyed and then recreated.

Both of the components I’m trying to recycle have a number of dynamically created child components inside of them, so the state of the vdom is going to be considerably different from the raw starting conditions of the initial page. Components like wonderful or complex don’t have any properties or any other data passed from the template… They are exactly as shown in the layout above. I’ve experimented with giving them a unique ID or key value that is shared across the templates (as well as nothing at all), but no matter what I have tried, the router push causes these components to destroy and re-render.

Trivial components like my header and footer recycle fine, I just want to make my more complex components behave likewise.

So my question centrally is, what allows or prevents recycling of components? What is examined to determine if a component can be recycled? Is there a way to signal that a component should be preserved/recycled between route changes? If not, what do I have to keep outside of the component to make it appear as a candidate for sticking around across transitions?

我曾经以为“键”属性在这里很神奇,但这似乎行不通,不幸的是,浏览该单词的Vue.js源表明它被广泛用于命名参数和局部变量……我相信Vue中一个称为“ patch()”的函数,该函数至少与新旧组件一致地更新vdom,但是坦率地说,其中的逻辑超出了我目前对Vue的了解。如果对Vue内部有更深入了解的人对代码的哪些部分可能有帮助,可以澄清我的想法,那么我将热衷于再次进行研究。

我觉得我已经为此追了好几天。任何想法或见解都将不胜感激。

第3490篇《如何在路由器更改之间使Vue.js组件可回收/持久化?》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

1个回答
蛋蛋 2020.03.24

(不确定这些解释是否足以满足您的要求,但是我还是要尝试回答它)

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

对于Nuxt来说,保持活动状态似乎还不可靠我建议您将所有数据保留在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来说,保持活动似乎还不可靠我建议您将所有数据保留在Vuex中,并根据Vuex中的数据渲染元素。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android