angular中的viewchild提供了访问从组件中访问模板中书写的DOM、子组件和指令的功能。
0. 基础知识
ViewChild
Property decorator that configures a view query. The change detector looks for the first element or the directive matching the selector in the view DOM. If the view DOM changes, and a new child matches the selector, the property is updated.
View queries are set before the ngAfterViewInit callback is called.
Metadata Properties:
selector - the directive type or the name used for querying.
read - read a different token from the queried elements.
相关钩子
钩子 | Purpose and Timing |
---|---|
ngAfterViewInit() | Respond after Angular initializes the component’s views and child views / the view that a directive is in. |
1. 访问DOM
DOM毕竟是前端的基础,在组件中怎么访问模板中写的DOM元素呢?
假如有个组件,OneComponent,他的模板中有个input标签,如下所示:
<input type="text">
如果在模板中的另外一个地方访问这个input,可以使用local variable,修改代码如下:
<input type="text" #inputText>
但是local variable到不了组件中,希望能在组件中访问inputText 。
原生的js中有个方法叫做element.querySelector, angular中有个ViewChild装饰器。
// inputText 作为参数, the name used for querying.
@ViewChild('inputText') inputElement: ElementRef;
ngAfterViewInit() {
console.log('我是原生元素哦', this.inputElement.nativeElement);
}
执行结果:
对于this.inputElement.nativeElement,这就是一个原生的DOM节点了。
2. 访问子组件
父组件通过使用子组件的selector在父组件的模板中使用子组件,就像是一个DOM元素的标签那样子。
定义一个子组件,就叫做TwoComponent吧,上面有个方法,主要代码如下:
@Component({
template: `<br>我是子组件。`,
selector: 'two-component'
})
export class TwoComponent {
.
.
.
sayName() {
console.log('我是子组件');
}
}
父组件的模板中:
<two-component #twocpt></two-component>
其中使用了本地变量,如此一来,至少父组件中至少有两种方法访问到子组件,
selector --- the directive type or the name used for querying.
一个是根据directive type,一个是根据the name 。
2.1 使用type访问子组件
@ViewChild(TwoComponent) ziComponent: TwoComponent;
// ngAfterViewInit 钩子中加入:
console.log('我是TwoComponent', this.ziComponent);
2.2 使用name访问子组件
@ViewChild('twocpt') twocomponent: TwoComponent;
//钩子ngAfterViewInit中加入:
this.twocomponent.sayName();
console.log(`this.ziComponent === this.twocomponent ? : `, this.ziComponent === this.twocomponent);
2.3 访问子组件中的DOM
ViewChild中的选择器可以传递第二个参数,
@ViewChild(TwoComponent, {read: ElementRef}) ziComponentEle: ElementRef;
这样就可以在父组件中访问到子组件的模板中的DOM元素,不过我们直接得到的是用ElementRef封装过的元素,通过其中的属性可以进一步得到元素DOM元素。
console.log('ziComponentEle:', this.ziComponentEle);
console.log('ziComponentEle.nativeElement:', this.ziComponentEle.nativeElement);
console.log('ziComponentEle.nativeElement.querySelector(\'div\'):', this.ziComponentEle.nativeElement.querySelector('div'));
3. 访问指令
写一个给input输入框赋值的指令,添加到父组件的模板的input中,
@Directive({
selector: '[appThreeDirective]'
})
export class ThreeDirective {
constructor(ele: ElementRef) {
ele.nativeElement.value = '我是指令赋值';
}
get directiveName() {
return '指令名';
}
}
<input type="text" #inputText appThreeDirective>
在父组件中通过指定类型来访问这个指令:
@ViewChild(ThreeDirective) triDirective: ThreeDirective;
// 钩子中加入:
console.log('我是指令名字', this.triDirective.directiveName);
参考文献:
https://alligator.io/angular/viewchild-access-component/