上週使用iframe實現顯示學生做業的過程走了些許彎路,當時使用模擬點擊按鈕實現的,後來因爲遮罩層的加入致使沒能實現效果,後來據說能夠用ngAfterViewInit實現,這就涉及到Anjular組件生命週期了,而後就瞭解一下生命週期的概念和用法。html
對於生命週期鉤子,官方文檔是這樣描述的:api
每一個組件都有一個被 Angular 管理的生命週期。Angular 建立和渲染組件及其子組件,當它們綁定的屬性發生變化時檢查它們,並在從 DOM 中移除它以前銷燬它們。app
Angular 提供了生命週期鉤子,把它們生命中的這些關鍵時刻暴露出來,賦予你在它們發生時採起行動的能力。ide
除了那些組件內容和視圖相關的鉤子外,指令有相同生命週期鉤子。函數
生命週期的順序是這樣的:
(紅色部分鉤子angular只會觸發一次,而綠色鉤子會觸發屢次)
ui
鉤子 | 用途及時機 |
---|---|
ngOnChanges() |
當 Angular(從新)設置數據綁定輸入屬性時響應。 該方法接受當前和上一屬性值的SimpleChanges對象 在ngOnInit() 以前以及所綁定的一個或多個輸入屬性的值發生變化時都會調用。 |
ngOnInit() |
在 Angular 第一次顯示數據綁定和設置指令/組件的輸入屬性以後,初始化指令/組件。在第一輪ngOnChanges() 完成以後調用,只調用一次。 |
ngDoCheck() |
檢測,並在發生 Angular 沒法或不肯意本身檢測的變化時做出反應。在每一個變動檢測週期中,緊跟在ngOnChanges() 和ngOnInit() 後面調用。 |
ngAfterContentInit() |
當 Angular 把外部內容投影進組件/指令的視圖以後調用。第一次ngDoCheck() 以後調用,只調用一次。 |
ngAfterContentChecked() |
每當 Angular 完成被投影組件內容的變動檢測以後調用。[ngAfterContentInit()](https://angular.cn/api/router/RouterLinkActive#ngAfterContentInit) 和每次ngDoCheck() 以後調用 |
ngAfterViewInit() |
當 Angular 初始化完組件視圖及其子視圖以後調用第一次ngAfterContentChecked() 以後調用,只調用一次。 |
ngAfterViewChecked() |
每當 Angular 作完組件視圖和子視圖的變動檢測以後調用。[ngAfterViewInit()](https://angular.cn/api/forms/NgForm#ngAfterViewInit) 和每次ngAfterContentChecked() 以後調用。 |
ngOnDestroy() |
每當 Angular 每次銷燬指令/組件以前調用並清掃。 在這兒反訂閱可觀察對象和分離事件處理器,以防內存泄漏。在 Angular 銷燬指令/組件以前調用。 |
一旦檢測到該組件(或指令)的輸入屬性發生了變化,Angular 就會調用它的ngOnChanges()
方法。 本例監控[OnChanges](https://angular.cn/api/core/OnChanges)
鉤子 該方法接受當前和上一屬性值的[SimpleChanges](https://angular.cn/api/core/SimpleChanges)
對象
當被綁定的輸入屬性的值發生變化時調用,首次調用必定會發生在ngOnInit()以前(在Angular官方給出的實例代碼中能夠印證這一點)。
this
官方給出的Demo對於該方法演示的效果是這樣的:url
@Input() hero:Hero; @Input() power:string;
對於這兩個數據綁定輸入屬性來講,只要它們的值發生改變,便會調用OnChange方法。spa
使用[DoCheck](https://angular.cn/api/core/DoCheck)
鉤子來檢測那些 Angular 自身沒法捕獲的變動並採起行動。code
用這個方法來檢測那些被 Angular 忽略的更改。
_AfterView_例子展現了[AfterViewInit](https://angular.cn/api/core/AfterViewInit)()
和[AfterViewChecked](https://angular.cn/api/core/AfterViewChecked)()
鉤子,Angular 會在每次建立了組件的子視圖後調用它們。
constructor(private logger:LoggerService){ this.logIt('AfterView constructor'); }
ngAfterViewInit(){ // viewChild is set after the view has been initialized this.logIt('AfterViewInit'); this.doSomething(); }
private logIt(method:string){ let child =this.viewChild; let message =`${method}: ${child ? child.hero :'no'} child view`; this.logger.log(message); }
初始化的時候,子組件未初始化完成,因此說"no child view",子組件初始化完成後,再次調用logIt方法,就有"child view"的信息了,在AfterViewInit以後,再進行AfterViewChecked操做,可是這些checked方法的調用是十分繁瑣的,一個地方改動,可能致使多個地方checked,牽一髮而動全身,而且頻率很高,想必這樣的方法在實際開發中不常常使用吧。
AfterContent例子展現了[AfterContentInit](https://angular.cn/api/core/AfterContentInit)()
和[AfterContentChecked](https://angular.cn/api/core/AfterContentChecked)()
鉤子,Angular 會在外來內容被投影到組件中_以後_調用它們。
AfterContent鉤子和AfterView類似。關鍵的不一樣點是子組件的類型不一樣。
[ViewChildren](https://angular.cn/api/core/ViewChildren)
,這些子組件的元素標籤會出如今該組件的模板_裏面_。[ContentChildren](https://angular.cn/api/core/ContentChildren)
,這些子組件被 Angular 投影進該組件中。AfterView對於子組件的引入是這樣的:
@Component({ selector:'after-view-parent', template:` <div class="parent"> <h2>AfterView</h2> <after-view *ngIf="show"></after-view> <h4>-- AfterView Logs --</h4> <p><button (click)="reset()">Reset</button></p> <div *ngFor="let msg of logger.logs">{{msg}}</div> </div> `, styles:['.parent {background: burlywood}'], providers:[LoggerService] })
而AfterContent是這樣引入的:
@Component({ selector:'after-content', template:` <div>-- projected content begins --</div> <ng-content></ng-content> <div>-- projected content ends --</div>` +` <p *ngIf="comment" class="comment"> {{comment}} </p> ` })
`<after-content> <app-child></app-child> </after-content>`
<ng-content>
標籤是外來內容的佔位符。 它告訴 Angular 在哪裏插入這些外來內容。 在這裏,被投影進去的內容就是來自父組件的<app-child>
標籤。
使用ngOnInit()
有兩個緣由:
一些清理邏輯_必須_在 Angular 銷燬指令以前運行,把它們放在ngOnDestroy()
中。
addHero(){ if(this.newName.trim()){ this.heroes.push(this.newName.trim()); this.newName =''; this.logger.tick(); }
reset(){ this.logger.log('-- reset --'); this.heroes =[]; this.logger.tick(); }
@Directive({selector:'[mySpy]'}) exportclassSpyDirectiveimplementsOnInit,OnDestroy{ constructor(private logger:LoggerService){} ngOnInit(){this.logIt(`onInit`);} ngOnDestroy(){this.logIt(`onDestroy`);} private logIt(msg:string){ this.logger.log(`Spy #${nextId++}${msg}`); } }
點擊Add以後,執行一次ngOnInit,點擊Reset以後,執行ngOnDestory
生命週期仍是比較明顯的。
Anjular的生命週期鉤子真的挺重要的,也感謝官方給的Demo,真的挺生動的,學起來也好理解,也好加深印象,也挺有趣的,要是專業課的老師也能拿個Demo講課,那也不至於聽天書。