我尝试使用transclusion 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-1
,component-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>
这可能吗?
答案 0 :(得分:1)
嗨,我想您正在尝试制作一种通用的smart-component
,并希望其子级(通过ng-content
)能够访问其范围,而不是您编写此模板时所使用的组件范围。我认为这是不可能的,并且对Transclusion所做的事情有些误解。
智能组件通常是非常特定的组件,可以将它们绑定到特定的路线和内容。如果不是这种情况,那么您最终将不得不在其中放置很多沉重的东西(例如注入的服务),而这在每种情况下都是不需要的。
如果设计得当,则包含可以帮助构成哑组件。因此,它们应该尽可能通用或灵活。
答案 1 :(得分:1)
首先,在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
。尽管上面的方法在某些情况下可以正常工作,但是如果我对您的理解是正确的,则希望从子组件与父组件进行通信。上面所有这些都将父组件放到了驾驶员座位上,这意味着它们并没有真正列出某些事件,而是可以访问子组件的API。另一方面,@Output
允许孩子通知其父母发生了事情。然后,父级可以侦听此事件并执行一些方法或任务。
如上所述,在大多数情况下,这是子组件与父组件之间进行通信的首选方式,因为它不会将子组件与父组件紧密耦合,反之亦然。愚蠢的组件仍然非常可重用,并且只向外部分发一些事件,然后父组件可以侦听并采取相应的行动。
这也使您可以根据自己的喜好来编写组件。您可以在智能组件中使用任何哑组件。这里唯一的要求是它们发出事件以通知其父项。
为了完整起见,您还可以将智能组件注入到哑组件中。看起来像这样:
@Component({
...
})
export class MyDumbComponent {
constructor(private smartComponent: ParentSmartComponent) { }
}
但是,我也不推荐这种方法,因为它再次将笨拙的组件与智能组件紧密耦合。正如@ n-sokolowski已经提到的那样,内容投影可以用作合成的手段,并且所组成的组件应尽可能地可重用和通用。
总而言之,只需在哑组件内部使用@Output
,然后发出父组件可以监听的特定事件即可。