如何在路由器更改之间循环/保留Vue.js组件?

时间:2018-05-30 20:58:18

标签: vue.js vue-router nuxt.js

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

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

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

相比之下,当路径发生变化时,简单的组件似乎根本就没有卸载,好像Vue不知何故知道这些组件在两个不同的布局中看起来是相同的,所以它不仅不会破坏/创建它们......将它们留在布局中,甚至不能卸载它们。

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

同样,为清楚起见,我并未提及" keep-alive"试图挂起内存中暂时从布局中删除的组件。我在观察并试图理解的内容似乎是一种不同的行为,其中Vue的某些部分将组件识别为两个布局之间的相同,并且它优化了销毁和(重新)创建这些组件。这是一个巨大的优化,但其行为似乎无法在我能找到的任何地方进行讨论或记录。

我有一个概念上像这样的Nuxt布局......

default.vue:

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

...我有几个看起来像这样的Nuxt页面......

页-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通信这些是渲染时的生物。

当我使用此。$ router.push()在这些页面之间导航时,我的页眉和页脚组件在路径导航中不受影响(我通过在生命周期钩子中放置一些控制台输出来验证这一点),但是这两个奇妙和复杂的组件被摧毁然后重新创建。

我正在尝试回收的两个组件都有许多动态创建的子组件,因此vdom的状态将与初始页面的原始启动条件有很大不同。像精彩或复杂的组件没有任何属性或从模板传递的任何其他数据......它们完全如上面的布局所示。我已尝试为它们提供一个在模板之间共享的唯一ID或键值(以及根本没有任何内容),但无论我尝试过什么,路由器推送都会导致这些组件被破坏并重新呈现。 / p>

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

所以我的问题集中在是什么允许或阻止组件的回收?检查什么以确定组件是否可以回收?有没有办法表明应该在路线变化之间保留/回收一个组件?如果没有,我必须保留在组件之外以使其显示为跨越过渡的候选者?

我曾经认为“关键”属性在这里很神奇,但这似乎不起作用,不幸的是,浏览这个单词的Vue.js源代码显示它被广泛用于命名参数和局部变量......我相信在Vue中有一个叫做“patch()”的功能,它至少可以使用旧的和新的组件来更新vdom,但坦率地说,那里的逻辑超出了我目前的Vue知识。如果对Vue内部有更好了解的人对代码的哪些部分可能有助于澄清我的想法有所了解,我会再次热衷于此。

我觉得我已经在这里追了好几天了。任何想法或见解都非常感激。

2 个答案:

答案 0 :(得分:2)

(不确定这些解释对你来说是否足够,但无论如何我只是想尝试回答)

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

对于Nuxt,keep-alive doesn't seem to be reliable yet。我建议您将所有数据保存在Vuex中,并根据Vuex中的数据渲染元素。

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

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

在此示例中,

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

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

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

在典型的(Not 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>会自动生成,您将无法像在正常的Vue项目中那样将<keep-alive>应用于它。

(再次)对于Nuxt,keep-alive doesn't seem to be reliable yet。我建议您将所有数据保存在Vuex中,并根据Vuex中的数据渲染元素。

答案 1 :(得分:1)

inertiajs 使用 vue 组件做到这一点

为布局创建一个 vue 模板

Layout.vue:

<template>
    <div>
        <!-- Your Layout code -->
    </div>
</template>

SomePage.vue:

<template>
    <div>
        <!-- Your specific page's code -->
    </div>
</template>

<script>
import Layout from 'path/to/Layout'

    export default {
        layout: Layout,
    }
</script>

SomePage 将包裹在 Layout

中回来

这个框架还有很多事情可以做,比如默认布局、特定目录中页面的布局等。

并且这种布局结构将确保在每个页面调用之间布局被持久化而不是破坏和重建每个页面调用,因此您可以保存滚动位置,在用户导航离开时继续播放音频等。所有这些都可以找到{ {3}}

您还可以使用渲染函数从 export 语句获取要显示的布局,查看 here git repo 以获取更多示例,也许可以考虑这个关于 Inertia.js、Vue 的精彩系列, 和 Laravel by PingCRM