Anjular生命週期鉤子

前言

上週使用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 銷燬指令/組件以前調用。

OnChanges:

一旦檢測到該組件(或指令)的輸入屬性發生了變化,Angular 就會調用它的ngOnChanges()方法。 本例監控[OnChanges](https://angular.cn/api/core/OnChanges)鉤子 該方法接受當前和上一屬性值的[SimpleChanges](https://angular.cn/api/core/SimpleChanges)對象
當被綁定的輸入屬性的值發生變化時調用,首次調用必定會發生在ngOnInit()以前(在Angular官方給出的實例代碼中能夠印證這一點)。
image.pngthis

官方給出的Demo對於該方法演示的效果是這樣的:url

Peek 2020-04-24 22-32.gif

@Input() hero:Hero;
@Input() power:string;

對於這兩個數據綁定輸入屬性來講,只要它們的值發生改變,便會調用OnChange方法。spa

DoCheck()

使用[DoCheck](https://angular.cn/api/core/DoCheck)鉤子來檢測那些 Angular 自身沒法捕獲的變動並採起行動。code

用這個方法來檢測那些被 Angular 忽略的更改。

Peek 2020-04-24 22-42.gif

AfterView

_AfterView_例子展現了[AfterViewInit](https://angular.cn/api/core/AfterViewInit)()[AfterViewChecked](https://angular.cn/api/core/AfterViewChecked)()鉤子,Angular 會在每次建立了組件的子視圖後調用它們。
Peek 2020-04-24 22-50.gif


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);
}

image.png
初始化的時候,子組件未初始化完成,因此說"no child view",子組件初始化完成後,再次調用logIt方法,就有"child view"的信息了,在AfterViewInit以後,再進行AfterViewChecked操做,可是這些checked方法的調用是十分繁瑣的,一個地方改動,可能致使多個地方checked,牽一髮而動全身,而且頻率很高,想必這樣的方法在實際開發中不常常使用吧。

AfterContent

AfterContent例子展現了[AfterContentInit](https://angular.cn/api/core/AfterContentInit)()[AfterContentChecked](https://angular.cn/api/core/AfterContentChecked)()鉤子,Angular 會在外來內容被投影到組件中_以後_調用它們。
Peek 2020-04-24 23-17.gif

AfterContent鉤子和AfterView類似。關鍵的不一樣點是子組件的類型不一樣。

  • AfterView鉤子所關心的是[ViewChildren](https://angular.cn/api/core/ViewChildren),這些子組件的元素標籤會出如今該組件的模板_裏面_。
  • AfterContent鉤子所關心的是[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>標籤。

OnInit()&## OnDestroy()

使用ngOnInit()有兩個緣由:

  1. 在構造函數以後立刻執行復雜的初始化邏輯
  2. 在 Angular 設置完輸入屬性以後,對該組件進行準備。

一些清理邏輯_必須_在 Angular 銷燬指令以前運行,把它們放在ngOnDestroy()中。
Peek 2020-04-24 23-38.gif

  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講課,那也不至於聽天書。

參考

angular--生命週期鉤子
生命週期鉤子
Anjular官方Demo

相關文章
相關標籤/搜索