angular2不推薦操作dom,但是實際應用中不可避免的需要使用到dom操作,怎么操作,官方文檔提供了一系列api(ElementRef,
ViewContainerRef ,
TemplateRef
)配合
@ViewChild或@ViewChildren就可以獲取到dom元素,但是這個過程中有些文檔未提及的坑,本人不小心踩進去,半天才爬出來,因此分享一下。
首先,需要在ng2的模板中使用 #bannersEL
定義一個模板局部變量,如:
<div class="swiper-wrapper" #bannersEL></div>
接着在模板對應的組件類中,使用組件中元數據@ViewChild來獲取模板局部變量的讀寫權限:
export class DemoComponent implements AfterViewInit {
@ViewChild("bannersEL") bannersEl: ElementRef; ngAfterViewInit(): void { console.log(this.bannersEl); } }
其中 @ViewChild("bannersEL") bannersEl: ElementRef 還可以使用如下語法限定局部變量的權限:
@ViewChild("bannersEL",{read:ElementRef}) bannersEl: ElementRef;
還需要注意點,this.bannersEl 對象獲取模板局部變量時機,僅在ngAfterViewInit生命周期之后才有,也就是說在組件構造器,及onint等生命周期時是獲取不到的。
然后還有一個最坑人的一點#bannersEL 模板局部變量最好寫在html元素的最前面,像上面那樣在模板標簽中定義模板局部變量,居然會導致組件中獲取不到,目前還不知道原因為何,正確寫法如下
<div #bannersEL class="swiper-wrapper">
但是你以為這樣就完了嗎,不,還有坑,如果你的模板中用了ngFor指令,並且循環綁定了模板局部變量,如:
<div #bannersEL class="swiper-slide" *ngFor="let banner of banners;t"></div>
//--------ts
@ViewChildren("bannersEL") bannersEl: QueryList<ElementRef>;
ngAfterViewInit(): void {
console.log(this.bannersEL.length)
}
//輸出結果是0,而實際上模版最終生成的div是有3個
解決以上問題的辦法就是模板代碼不動,js中做如下變動:
ngAfterViewInit(): void { this.bannersEl.changes.subscribe((list:QueryList<ElementRef>)=>{ if(list.length > 0){ list.forEach( el=>{ el.nativeElement.style.display="none"; }); } }); }
通過訂閱changes來獲取循環后得到div對象