angular - 如何在 Angular 6 中实现延迟组件投影?
问题描述
这是我将引用的代码示例。这是一个 stackblitz 项目,被剥离为解释问题所需的裸露组件。
所以我想做的是能够将一个组件作为另一个组件的子组件传递,但是这个父组件应该能够阻止它的创建,直到它决定要创建它。在示例中,app.component.html 文件是我<app-action>
作为孩子传递给的,<app-projector>
并且我希望<app-projector>
能够推迟<app-action>
一段时间的实际创建。
该<app-projector>
组件实际上ActionComponent
不能通过 ContentChildren 引用 ts 类,因为它应该可以是任何组件。
我当前的 stackblitz 示例尝试<ng-template>
在投影仪组件中使用,但正如您所见,它确实在投影仪组件决定实际渲染模板中的内容之前创建组件并运行组件生命周期函数。我想让它在我们准备好渲染作为内容传递的组件之前,我们不会启动生命周期函数或创建组件。
有任何想法吗?
解决方案
您的问题的根源是<ng-content>
在构建时发生 - 您投射到其中的任何组件都将在构建时而不是在运行时创建!(来源) 这就是为什么在你的 StackBlitz 中,<app-action>
组件甚至在它显示在屏幕上之前就已经开始计数了。而不是<ng-content>
用于延迟内容投影,您应该使用以下方法。
(查看StackBlitz 演示 ,看看它是否按预期工作)
创建结构指令
结构指令是改变 DOM结构的指令,例如通过添加、删除或操作元素。例如,ngIf
和ngFor
是结构指令。关于结构指令的事情是,如果你在指令前面放一个星号前缀,Angular 会自动将指令的宿主元素“转换”为一个。例如,这个:<ng-template>
*
<div *ngIf="myCondition">Lorem ipsum</div>
...由 Angular 自动转换为:
<ng-template [ngIf]="myCondition">
<div>Lorem ipsum</div>
</ng-template>
因此,如果我们创建了自己的结构指令delayedContent
并将其应用于组件/元素,例如<app-action>
:
<app-action *delayedContent></app-action>
...然后它将转换为:
<ng-template delayedContent>
<app-action></app-action>
</ng-template>
这是 TS 文件delayedContent
:
@Directive({
selector: '[delayedContent]'
})
export class DelayedContentDirective {
constructor(templateRef: TemplateRef<void>, projector: ProjectorComponent) {
projector.allDelayedContent.push(templateRef);
}
}
在这里,我可以使用Angular 生成TemplateRef
的元素来获取引用<ng-template>
,然后将其推送到父组件TemplateRef
中的数组。<app-projector>
在<app-projector>
组件中,我们现在可以将TemplateRefs
它们显示在您的<ng-container>
. 现在您的<app-action>
组件只会在createEmbeddedView()
被调用时创建,因此它会在显示时从 0 开始计数(而不是从 3 开始)。
@Component({
selector: 'app-projector',
templateUrl: './projector.component.html'
})
export class ProjectorComponent implements AfterViewInit {
// All the TemplateRefs to the delayed content will be stored in this array
allDelayedContent: TemplateRef<void>[] = [];
@ViewChild('container', { read: ViewContainerRef }) _container: ViewContainerRef;
constructor() { }
ngAfterViewInit() {
// Show this after 3 seconds
setTimeout(() => {
this._container.createEmbeddedView(this.allDelayedContent[0]);
}, 3000)
// You can add other elements to the `allDelayedContent` array and show them here
// Show this after 5 seconds
setTimeout(() => {
this._container.createEmbeddedView(this.allDelayedContent[1]);
}, 5000)
// Show this after 7 seconds
setTimeout(() => {
this._container.createEmbeddedView(this.allDelayedContent[2]);
}, 7000)
}
}
查看第二个 StackBlitz 演示。它具有delayedContent
结构指令的修改版本,可让您直接在 HTML 中指定延迟时间,如下所示:
<app-projector>
<app-action *delayedContent="3000"></app-action>
<div *delayedContent="2000">Some delayed content</div>
<div *delayedContent="6000">More delayed content</div>
<app-projector>
推荐阅读
- python - 为什么更新类属性不会更新类的所有实例?
- python - roslibpy 消息不包含多个键值对
- powershell - 使用 PowerShell 同时覆盖多个 *.txt 文件的全部内容
- webpack - css 加载器不工作 - webpack 无法识别 css 类型文件
- sql - 我可以在 SQL 中制作数据透视表吗
- .net - Application Insights 如何拦截 SQL 调用?
- machine-learning - 如何区分 OCR 中的斜线零和八(0-> 8)
- python - 基于先前值和 Python 上的 ID 的重复总和?
- java - 将带括号的逗号分隔字符串传递给列表
- linq - 使用 linq 查询的自定义类型的 F# Linq 扩展方法