熟悉Angular1.X版本的同学应该知道,Angular1.X在指令中的link函数中提供了element参数,让我们可以对元素的原生dom进行获取和操作,在新版本的Angular中,则以decorator的形式,提供了ViewChild,ViewChildren,以及对应的ContentChild和ContentChildren让我们可以获取元素的dom对象,本文讲解较为常用的ViewChild和ViewChildren这两个decorator
注意:使用时需要从@angular/core中引入ViewChild和ViewChildren
ViewChild:
ViewChild可以获取到当前组件视图中的单个元素,获取方式有两种:
第一种(通过模板引用变量):
<main #mychild> <!-- my html content --> </main>
@ViewChild('mychild') myChild : ElementRef constructor() { } ngAfterViewInit() { console.log(this.myChild) }
第二种(直接指定组件类):
<my-child></my-child>
@Component({ selector: 'my-child',templateUrl: './xxxxx.html' }) class ChildComponent { constructor() { } }
@ViewChild() myChild : ChildComponent; ngAfterViewInit() { console.log(this.myChild) }
这两种方式有何区别呢?
区别在于,第一种方式取得的mychild变量是经过包装的,他是一个ElementRef类,其中包含了nativeElement这个属性,这个属性的值就相当于通过原生dom操作取得的element。打印结果如下图:
而如果通过第二种方式,我们需要为组件类注入ElementRef,才能够取得nativeElement,如下:
//先引入ElementRef //import {ElementRef} from '@angular/core'; @Component({ selector: 'my-child',templateUrl: './xxxxx.html' }) class ChildComponent { constructor(public ele: ElementRef) { } }
注意,为ChildComponent实例化ElementRef时,需要用public标识符,private的话会导致外部无法取得该ele变量(那你就得专门为其实现一个get方法)
这时,我们就能通过this.mychild.ele.nativeElement来取得其DOM元素了
ViewChildren:
对应的,ViewChildren,顾名思义是可以获得一个视图集合,它是一个类数组的形式,使用方式与ViewChild相似,但需要以QueryList的形式存在:
@ViewChildren(ChildComponent) myChild : QueryList<ChildComponent>; ngAfterViewInit() { console.log(this.myChild) }
QueryList是个什么概念?
我们看看官方文档的解释:
我看不懂英文,总的来说就是一个结果集,这个结果集在你的Angular应用更新完成时也随之更新,
但里面的结果是不可以直接访问和修改的(很合理)。
我们先来看看打印出来的ViewChildren实例长啥样:
可以发现我们想要的取得的结果--(_results)属性,然而这个_results属性是private的,我们无法直接取得(经实践可以通过mychild['_results']的方法来获取,但这也已经超出了ts的范围,也是不安全的做法,应该杜绝),但我们有两种方式可以遍历这个_results数组:
第一是通过mychild.forEach()方法,第二是先调用QueryList原型中的toArray()方法,接着再用数组的方式进行处理
监听视图变化:
假设我们有一个由多个my-child组成列表,它可以添加或移除my-child组件,我们希望在my-child集合被改动时都做出回应,此时Observable就派上用场了,QueryList为我们提供了一个changes的Observable:
我们只需要订阅它就可以完成这个需求了:
this.mychild.changes.subscribe((data)=>{ // do something })
细节:
为何是ngAfterViewInit?
注意到我们获取mychild都是在ngAfterViewInit的生命周期钩子函数中进行的(生命周期的流程详见https://www.angular.cn/docs/ts/latest/guide/lifecycle-hooks.html#!#onchanges)
这是因为mychild是在ngAfterViewInit完成后才能获取到值,所以也可以在ngAfterViewChecked中获取,但前者是最快能获取到的地方,所以在ngAfterViewInit之前的阶段,比如ngOnInit,ngOnChanges都是无法获取到的
还有其他细节?欢迎评论补充,我会尽量完善。
原文链接:https://www.f2er.com/angularjs/147482.html