我正在玩@ViewChild / @ ContentChild,我很惊讶地看到@ViewChild不在内部指令中运行并且对于component.But在指令中工作正常它不起作用。我尝试使用AfterViewInit钩子,所以生命周期钩子不是原因。其他问题在这里,请找到下面的代码。
app.component.html
<div appMain >
<div #testContentDiv style="background-color: grey">
<p>This is the first p tag</p>
<p>This is the second p tag</p>
</div>
<div #testViewDiv style="background-color: yellow">
<p>This is the first p tag</p>
<p>This is the second p tag</p>
</div>
<app-test-child></app-test-child>
</div>
test-dir.ts - 指令
import { Directive, ViewChild, ElementRef, OnInit, AfterViewInit, AfterContentInit, ContentChild } from '@angular/core';
@Directive({
selector: '[appMain]'
})
export class MainDirective implements OnInit, AfterContentInit, AfterViewInit {
constructor() { }
// tslint:disable-next-line:member-ordering
@ContentChild('testContentDiv') testContent: ElementRef;
@ViewChild('testViewDiv') testView: ElementRef;
ngOnInit() {
//Called after the constructor, initializing input properties, and the first call to ngOnChanges.
//Add 'implements OnInit' to the class.
// console.log(this.test.nativeElement);
}
ngAfterContentInit() {
//Called after ngOnInit when the component's or directive's content has been initialized.
//Add 'implements AfterContentInit' to the class.
console.log('Content Div: ngAfterContentInit: ' + this.testContent.nativeElement);
// console.log('View Div: ngAfterContentInit: ' + this.testView.nativeElement);
}
ngAfterViewInit() {
//Called after ngAfterContentInit when the component's view has been initialized. Applies to components only.
//Add 'implements AfterViewInit' to the class.
console.log('Content Div:ngAfterViewInit: ' + this.testContent.nativeElement);
console.log('View Div: ngAfterViewInit: ' + this.testView.nativeElement);
}
}
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = "App works";
constructor() {
}
}
Angular中有三种指令:
组件 - 带模板的指令。
结构指令 - 通过添加和删除DOM元素来更改DOM布局。
属性指令 - 更改元素,组件或其他指令的外观或行为。
因此,根据定义,组件是唯一带有template
的指令,因此您只能为组件找到@ViewChild
。
阅读更多关于它here。
希望这可以帮助!!
至少从Angular v6.x开始:
根据Angular source code for directives,确实可以选择孩子。但是,仅使用@ViewChildren
或@ContentChildren
装饰器的标准方法似乎对我不起作用。此外,尽管有文档,我仍然无法让@ViewChildren
工作。
然而,@ContentChildren
确实对我有用。你需要使用queries属性来装饰Directive本身(为了清楚起见,这个指令是愚蠢的,你仍然需要一个选择器和其他东西来使它工作):
@Directive({
queries: {
// Give this the same name as your local class property on the directive. "myChildren" in this case
myChildren: new ContentChildren(YourChild),
},
})
export class MyDirective implements AfterContentInit {
// Define the query list as a property here, uninitialized.
private myChildren: QueryList<YourChild>;
/**
* ngAfterContentInit Interface Method
*/
public ngAfterContentInit() {
// myChildren is now initialized and ready for use.
}
}
这对我来说已经足够了,所以我不会浪费更多的时间来弄清楚为什么ViewChildren
不起作用。我理解ViewChildren
和ContentChildren
is之间的区别,ContentChildren
从<ng-content>
标签中选择,ViewChildren
直接从视图本身中选择。所以,这种行为对我来说似乎是倒退的,但可能有其正当理由。
正如预期的那样,ContentChildren
在ngAfterContentInit
挂钩之前是不可用的,所以不要让那个人咬你。