不创建新指令的解决方案是利用@ViewChild 和@ViewChildren 的行为:
配置视图查询的属性装饰器。变化检测器
查找第一个元素或与选择器匹配的指令
视图 DOM。如果视图 DOM 发生变化,并且新的子节点匹配
选择器,属性已更新。
1。查看孩子
重要的部分是如果视图 DOM 发生变化,这意味着在这种情况下,这只会在元素被创建或销毁时触发。
首先为元素声明一个变量名,对于我使用的示例#userContent
<div #userContent *ngIf="user$ | async as user" class="container">
<p>user.name</p>
</div>
然后在你的组件中添加一个@ViewChild 引用:
@ViewChild('userContent') set userContent(element) {
if (element) {
// here you get access only when element is rendered (or destroyed)
}
}
此解决方案在another question 内部提供,@ViewChild 行为细节也可在here 获得。
2。查看儿童
另一个不使用新指令的解决方案是订阅
@ViewChildren 改变 observable,而不是使用 @ViewChild 这么说:
@ViewChildren('userContent')
private userContent: QueryList<any>;
然后订阅它改变 observable:
userContent.changes.pipe(takeUntil(this.$d)).subscribe((d: QueryList<any>) => {
if (d.length) {
// here you get access only when element is rendered
}
});
我更喜欢最后一种方式,因为对我来说,处理 observables 比处理 setter's 内部的验证更容易,而且这种方式更接近“事件”概念。
关于 Observables 的注意事项:
所有的 observable 都需要取消订阅,否则会引发内存泄漏;有很多方法可以防止这种情况发生,作为推荐,我最喜欢的方法是 RxJs 函数takeUntil,这部分:pipe(takeUntil(this.$d)) 以及您的ngOnDestroy 方法中的以下内容:
private $d = new Subject();
ngOnDestroy() {
this.$d.next();
this.$d.complete();
}
我推荐这种方式的原因是因为实现它的额外代码量也非常少; 您可以对组件中的所有订阅使用相同的变量 (this.$d)。有关取消订阅方法的更多详细信息/选项,请参阅this other related question/answer。