首页 > 解决方案 > 在嵌入的组件中使用父范围/方法/属性

问题描述

我尝试使用嵌入 n angular6 并且无法使我的范围变直。

<component-smart1
  [someObject]="myObject"
  [someService]="saidService">

  <component-dumb-1
    [specificObject]="getSpecificObject()"></component-dumb-1>

  <component-dumb-2
    [specificObject]="getSpecificObject()"
    (someEvent)="handleEvent()"></component-dumb-2>

</component-smart1>

现在我希望哑组件(component-dumb-1component-dumb-2)使用智能组件(component-smart1)范围/方法/属性。

我的目标是能够在嵌入中用不同的组件组成不同的变体,所有这些都使用智能组件中的相同方法。例如:

<component-smart1
  [someObject]="myObject"
  [someService]="saidService">

  <component-dumb-1
    [specificObject]="getSpecificObject()"></component-dumb-1>

  <component-dumb-2
    [specificObject]="getSpecificObject()"
    (someEvent)="handleEvent()"></component-dumb-2>

  <component-dumb-3
    [specificObject]="getSpecificObject()"
    (someOtherEvent)="handleOtherEvent()"></component-dumb-3>

</component-smart1>

这可能吗?

标签: angularscopeng-content

解决方案


首先,在 Angular >= 2.x 中不再有作用域。组件模板的执行上下文总是它的组件类。但是,有几种方法可以在 和 之间进行parent => child通信child => parent

第一种方法是使用@ContentChildren将返回一个QueryList. 这需要您添加模板引用变量,例如#myChild. 这就是您的模板的样子:

<component-smart1>
  <component-dumb-1 #myDumbChild></component-dumb-1>
  <component-dumb-2 #myDumbChild></component-dumb-2>
</component-smart1>

使用@ContentChildren装饰器,您可以查询这些引用变量并访问哑组件公共 API。

另一种方法是利用 DI 系统的强大功能。例如,您可以在子组件级别配置提供程序,使用抽象类作为注入令牌和策略useExisting。这将允许您查询一个令牌以获取特定类型的所有内容子项。这是一个例子:

abstract class MyDumbComponent {
  // some properties here
  // some methods here
};

@Component({
  selector: 'my-dumb-component',
  providers: [
    { provide: MyDumbComponent, useExisting: DumbComponentA }
  ]
})
export class DumbComponentA implements MyDumbComponent {
  ...
}

注意,我在这里使用了一个抽象类作为标记,因为接口在编译后会消失,其次,我喜欢为具有相同方法的组件定义一些通用的“接口”。

在您的父组件中,您可以像这样查询它们:

@Component({
  ...
})
export class ParentSmartComponent { }
  @ContentChildren(MyDumbComponent) myDumbComponents: QueryList<MyDumbComponent>;

  ngAfterContentInit() {
    // here you'll have access to your dumb components
  }
}

第三种首选方法是使用@Output's. 虽然上述方法在某些情况下可以正常工作,并且如果我理解正确,您希望从子组件与父组件进行通信。以上所有内容都将父组件置于驾驶员座位上,这意味着它们并没有真正列出某些事件,而是可以访问子组件的 API。@Output另一方面,允许孩子通知其父母发生了什么事。然后父级可以监听这个事件并执行一些方法或任务。

如前所述,在大多数情况下,这是子组件和父组件之间通信的首选方式,因为它不会将您的子组件与父组件紧密耦合,反之亦然。哑组件仍然非常可重用,并且仅将一些事件分派到外部,然后父组件可以侦听并采取相应的行动。

这也允许您根据自己的喜好组合组件。您可以在智能组件中使用任何哑组件。这里唯一的要求是它们发出事件以通知其父级。

为了完整起见,您还可以将智能组件注入到哑组件中。这就是它的样子:

@Component({
  ...
})
export class MyDumbComponent {
  constructor(private smartComponent: ParentSmartComponent) { }
}

但是,我也不推荐这种方法,因为它再次将您的愚蠢组件与您的智能组件紧密耦合。正如@n-sokolowski 已经提到的,内容投影可以用作组合的手段,并且您的组合组件应该尽可能可重用和通用。

总而言之,只需@Output在您的哑组件中使用 ' 并发出父组件随后可以侦听的特定事件。


推荐阅读