上一章学习了在组件类中通过ViewChild去引用模板中的元素,是通过引用名引用的。但是ViewChild不只可以指定引用名引用,也可以指定组件类型来引用。
@ViewChild
比如引用image-slider组件,那么使用方法如下:
<app-image-slider [sliders]="imageSliders"></app-image-slider>
@ViewChild('ImageSliderComponent', { static: true }) imageSlider: ImageSliderComponent;
所以,如果想引用模板中的Angular组件,@ViewChild中,可以使用引用名,也可以使用组件类型。
@ViewChildren
上面说的是单个模板的引用,如果想引用多个模板元素该如何处理呢?
比如,想选中image-slider中所有的轮播图图片,如果继续使用@ViewChild
,那么对于相同命名的,ViewChild只会选中ngFor
中的第一个元素,并不会选中整个img元素。这就引出了@ViewChildren
可以选中整个img数组。
<img #img *ngFor="let slider of sliders" [src]="slider.imgUrl" [alt]="slider.caption">
@ViewChildren('img') imgs: QueryList<ElementRef>;
所以,可以使用@ViewChildren
,在@ViewChildren
中可以使用引用名或者使用Angular组件/指令的类型。声明类型为QueryList<?>
打印出imgs看一下效果:
可以看出这个时候并没有打印出imgs属性,为什么呢?这就用到前面学习的知识了:组件的生命周期。
ngOnInit的时候,视图并没有初始化完成。ngAfterViewInit是视图初始化完成。
再来看一下效果:
Renderer2
之前讲过,Angular是不推荐直接操作DOM的。那么Angular推荐使用什么呢?
没错,推荐使用Renderer2。
先来看一下用法示例
那么问题来了,为什么我们要这样用呢?直接写不好吗?
解释一下:如果直接操作DOM,即自己写html节点,可能会造成XSS攻击。比如我们的应用是允许用户自己写一段Html代码传到组件类中,这个时候你不确定用户是否是恶意写入的攻击代码,这其实就属于XSS攻击。
Renderer2是渲染器,默认情况下,Angular会把模板渲染成DOM,同时会检查恶意代码的注入。
总结
@ViewChild用来在类中引用模板中的视图节点,既可以是Angular组件,也可以是HTML元素
在AfterViewInit中可以安全的使用@ViewChild引用的元素
推荐使用Renderer2操作DOM元素