紅色的被調用一次,綠色的會被調用屢次,變化檢測中的四個方法和組件初始化中的四個方法是同樣的。css
組件初始化:前面四個初始化屬性,後面四個渲染視圖。html
變動檢測:使屬性值和頁面展現保持一致。java
組件生命週期順序:
1.constructor:構造器函數,實例化對象,並用於注入服務
2.ngOnChanges:初始化 輸入屬性,檢測到@Input輸入數據變化時執行,首次觸發發生在ngOnInit前。注意對象的屬性發生變化時監聽不到
3.ngOnInit:初始化 除輸入屬性以外其餘的屬性,一般會設置一些初始值(若是初始化的邏輯須要依賴@Input輸入屬性,那就必定要寫在ngOnInit中,而不要寫在構造函數中)
4.ngDoCheck:組件變動檢測時執行
5.ngAfterContentInit:投影內容 初始化到組件以後執行
6.ngAfterContentChecked:投影內容 變動檢測以後執行
7.ngAfterViewInit:視圖 初始化以後執行
8.ngAfterViewChecked:視圖 發生變化檢測以後執行,這個能夠用來保證用戶視圖的及時更新
9.ngOnDestroy:組件註銷時的清理工做,一般用於移除事件監聽,退訂可觀察對象等json
1.onChanges瀏覽器
當@input屬性(輸入屬性)發生變化時,會調用;當輸入屬性爲對象時,當對象的屬性值發生變化時,不會調用,當對象的引用變化時會觸發。app
例子:函數
child.ts代碼片斷:this
@Input()
greeting: string;
@Input()
user:{name:string};
如上,greeting改變會觸發ngOnChanges事件,而user.name改變不會觸發ngOnChanges事件,由於greeting是字符串是不可變對象(每次值改變的時候都會建立一個新的字符串,而後把引用指向新的字符串),而user是可變對象,修改姓名的值的時候並無改變user對象的引用。那麼怎麼監控可變對象呢,用doCheck。spa
2.變動檢測機制code
angular使用package.json文件中dependencies引入的zone.js來實現變動檢測機制。
保證屬性的變化和頁面的變化是一致的,瀏覽器中發生的任何變化都會觸發變動檢測機制,好比點擊按鈕,輸入數據。。。
Default策略:默認,無論變動發生在哪一個組件上,zone都會檢測整個組件樹。
OnPush策略:若是有某個組件聲明自身的策略爲onPush,只有當這個組件的@input輸入屬性發生變化時,zone纔會檢測該組件及其子組件。
例子:
變動檢測機制的實現須要實現DoCheck接口中的ngDoCheck()方法。頁面上隨便一個點擊都會觸該方法,好比點擊輸入框等,全部在使用上要很是當心。
import {Component, OnInit,Input,,DoCheck} from '@angular/core'; @Component({ selector: 'app-child', templateUrl: './child.component.html', styleUrls: ['./child.component.css'] }) export class ChildComponent implements DoCheck{ constructor() {} ngDoCheck():void{ //組件變動時觸發 } }
須要注意的是,當變動檢測機制發生的時候,不光是doCheck()方法,全部含check關鍵字的方法(包括ngAfterContentChecked(),ngAfterViewChecked())都會被調用。因此這些方法也都要很是當心的使用。
3.view鉤子
1.父組件調用子組件的方法
child.component.ts
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-child', templateUrl: './child.component.html', styleUrls: ['./child.component.css'] }) export class ChildComponent implements OnInit { constructor() { } ngOnInit() {} //子組件方法 greeting(name:string){ console.log("hello"+name); } }
方法一:在模板中經過對子組件標籤的模板變量( #變量名)直接調用用子組件方法:
parent.component.html
<!--定義模板變量child1--> <app-child #child1></app-child> <app-child #child2></app-child> <!--在模板中調用子組件greeting()方法--> <button (click)="child2.greeting('Jerry')"></button>
方法二:在組件類中經過@ViewChild裝飾器聲明子組件的對象,而後調用子組件對象中的方法
parent.component.ts
import { Component,ViewChild } from '@angular/core'; import {ChildComponent} from "./child/child.component"; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { //經過@ViewChild獲取的子組件對象 @ViewChild("child1") child1:ChildComponent constructor(){} ngOnInit():void{ this.child1.greeting("Tom");//調用方法 } }
2.AfterViewInit和AfterViewChecked
在整個組件模板的內容顯示完成,即都已經呈現給用戶看以後,會調用這兩個方法;
初始化方法AfterViewInit()優先被調用,並且只調用一次,AfterViewChecked後調用;
若是存在子組件,則先調用子組件的,再調用父組件的;
不要在這兩個方法中去改變視圖中綁定的東西,若是想改變也要寫在一個setTimeout裏邊,以下:
例子中,整個視圖已經初始化完畢了,又要去修改與視圖有綁定的message,會報錯,
message:string; ngAfterViewInit(): void { console.log("父組件的視圖初始化完畢"); this.message="Hello"; }
改爲:
ngAfterViewInit(): void { console.log("父組件的視圖初始化完畢"); setTimeout(()=>{ this.message="Hello"; },0); }
在javaScript另外一個運行週期去運行
4.ngContent
ngContent指令用來將父組件模板中的任意html片斷投影到子組件中。
例子:
child.html
<div> <h2>子組件</h2> <ng-content select=".header"></ng-content> <ng-content select=".footer"></ng-content> </div>
parent.html
<div> <h2>父組件</h2> <app-child> <div class="header">頁頭</div> <div class="footer">頁腳</div> </app-child> </div>
如上,子組件經過<ng-content>指令的select屬性,分別將父組件的頁頭和頁腳兩個div投影到子組件中。
ngAfterContentInit和ngAfterContentChecked在投影的模板被渲染以後調用。
5.ngOnDestroy
從A路由跳到B路由後,A路由對應的組件會執行ngOnDestroy