Angular 6 - 多个子组件应该是同一个实例

Posted

技术标签:

【中文标题】Angular 6 - 多个子组件应该是同一个实例【英文标题】:Angular 6 - Multiple child components should be of same instance 【发布时间】:2018-12-04 20:21:28 【问题描述】:

我简化了我的问题:

<div *ngIf="layout1" class="layout1">
  <div class="sidebar-layout1">
     some items
  </div>
  <child-component [something]="sth"></child-component>
</div>
<div *ngIf="!layout1" class="layout2">
  <child-component [something]="sth">
    <p>some content...</p>
  </child-component>
</div>

我有一个父组件,它具有正常布局(layout1)和全屏布局(layout2)的可能性(在全屏模式下,子组件应该全屏)。问题是, 当我使用 *ngIf 更改布局时,子组件被销毁并生成一个新组件。我想拥有相同的实例,不要丢失子组件的重要信息,避免一些 a​​pi 调用。

有什么方法可以实现子组件不会被销毁,或者有没有比 ngIf 更好的方法?

对于父组件中的不同布局,我只需要一个子组件实例。

【问题讨论】:

但使用 [hidden] 仍然占用空间。相反,在 ngStyle 上设置 display:none。这只是我的假设。试一试。我需要知道“!layout1”是任何标志或布尔值吗? layout1 只是一个布尔标志,我在按钮单击事件上更新 好的。尝试这个。再添加一个标志,例如 if(this.paraentLayout == false) dont made change in child 即 *ngIf == ' parentLayout == false ? classA : ClassB' 我将只使用一个孩子和 ngClass 跨度> 【参考方案1】:

您可能已经注意到,如果您使用*ngIf 隐藏元素,则会创建一个新组件。这是我们将努力关注并尽量避免创建新组件的内容。

为此,我们可以使用“切换器布局”并将子组件作为内容传递

<app-layout-switcher [layout1]="layout1">
  <ng-container>
    <child-component
      *ngIf="sth$ | async as sth; else loading"
      [something]="sth"
    >
      <p>some content...</p>
    </child-component>
    <ng-template #loading>
      <h1>Loading...</h1>
    </ng-template>
  </ng-container>
</app-layout-switcher>

我添加了一个模拟 http 调用来显示加载。

在我们的app-layout-switcher 组件中,我们可以根据需要在布局之间切换。我们会将child-component 传递到模板中,以便能够在布局中重用它

<div *ngIf="layout1">
  <app-layout-1>
    <ng-template [ngTemplateOutlet]="childComponent"></ng-template>
  </app-layout-1>
</div>

<div *ngIf="!layout1">
  <app-layout-2>
    <ng-template [ngTemplateOutlet]="childComponent"></ng-template>
  </app-layout-2>
</div>

<ng-template #childComponent>
  <ng-content></ng-content>
</ng-template>

现在我们可以在布局中使用模板

<header>
  <h1>Layout 1</h1>
</header>
<main>
  Contents in Layout 1
  <div>
    <ng-content></ng-content>
  </div>
</main>

<footer>Layout 1 Footer</footer>

我们现在只使用该组件的一个实例。为了确认这一点,我在演示中添加了一个文本字段。你会注意到切换布局时数据是持久化的

See this Demo

【讨论】:

嗨@Owen Kelvin。谢谢你的回答。它适用于一个组件。但是对于在&lt;ng-content&gt; 标签中使用select 的多个子组件,它是如何工作的呢?似乎选择标签在布局切换器中丢失了。【参考方案2】:

使用 [hidden] 属性与反向逻辑相反,它会防止元素被破坏。

<div [hidden]="!layout1" class="layout1">
...
</div>
<div [hidden]="layout1" class="layout2">
...
</div>

我 hidden 只是通过更改显示样式来隐藏/显示带有 css 的 DOM 元素

【讨论】:

但使用 [hidden] 仍然占用空间。相反,在 ngStyle 上设置 display:none。这只是我的假设。试一试 但我仍然有两个不同的子组件实例。我需要一种方法来只拥有一个子组件实例以不丢失它的信息【参考方案3】:

您可以通过几个步骤实现:

    使用此命令创建服务:
ng generate service data-passing
    在该服务中定义两个变量来保存每个组件的数据:
import Injectable from '@angular/core';

@Injectable(
  providedIn: 'root',
)
export class DataPassingService 
  public firstComponentData;
  public secondComponentData;

  constructor()  


    在您的组件中使用服务:
import DataPassingService from '...';

...
constructor(public dataPassingService: DataPassingService) 

    将每个组件数据存储在相对变量中:
setDate(first, second) 
  this.dataPassingService.firstComponentData = first;
  this.dataPassingService.secondComponentData = second;

    像以前一样使用*ngIf 来控制组件的可见性:
<div *ngIf="layout1" class="layout1">
  <div class="sidebar-layout1">
     some items
  </div>
  <child-component [something]="dataPassingService.firstComponentData"></child-component>
</div>
<div *ngIf="!layout1" class="layout2">
  <child-component [something]="dataPassingService.secondComponentData">
    <p>some content...</p>
  </child-component>
</div>

【讨论】:

【参考方案4】:

当您想在两种不同的布局中显示相同/不同的细节时:

为状态管理实现秋田商店 https://datorama.github.io/akita/docs/store 从父组件本身的服务中获取所需的所有数据。 将接收到的数据从服务更新到存储中。 通过在两种布局中使用查询来订阅商店。 更新用户在商店中所做的最新更新。

【讨论】:

以上是关于Angular 6 - 多个子组件应该是同一个实例的主要内容,如果未能解决你的问题,请参考以下文章

Angular 在父子组件中使用多个服务实例

如何使用Angular 6在一个输入中将多个对象发送到嵌套子组件

我可以为 Angular 6 中模块的所有子路由加载一个组件吗?

Angular 6 多个 @input() 级别

Angular 6 Change detection - 如何设置子组件?

将 Angular Reactive FormControls 传递给子组件