這個問題是上週的,當時以爲這個問題的解決辦法太簡單了,不用寫博客記錄,可是潘老師今天今天又遇到了須要使用這個的地方,感受問題雖然不難,可是,寫篇博客,方便本身查詢,也給了其餘人搜索到解決辦法的機會。html
項目中使用到了ifame,理想狀態是:當點擊ifame中的按鈕時,將會調用經過angular寫的一個函數,函數將會修改一個ngif的判斷條件,顯示一個彈窗,
但現實是:當點擊ifame中的按鈕時,將會調用經過angular寫的一個函數,函數將會修改一個ngif的判斷條件,而後就沒有而後了.typescript
開始的時候本身直接懵了, 方法確實執行了, 但界面沒修改, 問了問潘老師, 潘老師說看看生命週期函數是否執行了, 果真, 全部的生命週期函數都沒有調用。segmentfault
既然生命週期函數沒調用,咱們讓他調用不就好了,值已經變化了,可是界面不變化,說明,angular 不知道值變化了,因此咱們可讓angular 主動進行變動檢測,讓它知道已經發生了變化。
對此咱們可使用ChangeDetectorRef
promise
Angular 在整個運行期間都會爲每個組件建立 ChangeDetectorRef 的實例,該實例提供了相關方法來手動管理變化監測。有了這個類,咱們本身就能夠自定義組件的變化監測策略了,如中止/啓用變化監測或者按指定路徑變化監測等等。
它有如下方法:瀏覽器
因此,咱們可使用detectChanges()
來達到目標app
// 在組件中注入 constructor(private changeDetectorRef: ChangeDetectorRef) { } // 直接使用 test() { this.changeDetectorRef.detectChanges() }
總結起來, 主要有以下幾種狀況:異步
setTimeout
,setInterval
Angular並非捕捉對象的變更,它採用的是在適當的時機去檢驗對象的值是否被改動,這個時機就是這些異步事件的發生。
這個時機是由 Zone.js
去掌控的,它獲取到了整個應用的執行上下文,可以對相關的異步事件發生、完成或者異常等進行捕獲,而後驅動 Angular 的變化監測機制執行。函數
實際上Zone,js
有一個叫猴子補丁的東西。在Zone.js
運行時,就會爲這些異步事件作一層代理包裹,也就是說Zone.js運行後,調用setTimeout、addEventListener
等瀏覽器異步事件時,再也不是調用原生的方法,而是被猴子補丁包裝事後的代理方法。代理裏setup了鉤子函數, 經過這些鉤子函數, 能夠方便的進入異步任務執行的上下文.this
//如下是Zone.js啓動時執行邏輯的抽象代碼片斷 function zoneAwareAddEventListener() {...} function zoneAwareRemoveEventListener() {...} function zoneAwarePromise() {...} function patchTimeout() {...} window.prototype.addEventListener=zoneAwareAddEventListener; window.prototype.removeEventListener=zoneAwareRemoveEventListener; window.prototype.promise = zoneAwarePromise; window.prototype.setTimeout = patchTimeout;
關於Zone.js
的詳細內容能夠看這篇文章。spa
angular 提供了兩種變動檢測策略,除了上述得Default外還有一種OnPush
的檢測機制
OnPush 與 Default 之間的差異: 當檢測到與子組件輸入綁定的值沒有發生改變時,變化檢測就不會深刻到子組件中去。
app.comonent.ts
@Component({ selector: 'app-root', template: ` <h1>{{title}}</h1> <h2>user.name: {{user.name}}</h2> <button type="button" (click)="changeUserName()"> 改變屬性 </button> <button type="button" (click)="changeUserObject()"> 改變對象 </button> <app-test [user]="user"></app-test> `, }) export class AppComponent { title = 'OnPush Demo'; user: User = new User({name: 'yunzhi'}); changeUserName() { this.user.name = 'new name'; } changeUserObject() { this.user = new User({name: 'new user'}); } }
test.component.ts
@Component({ selector: 'app-test', template: ` <div> <h3>test 組件</h3> <p> <label>User:</label> <span>{{user.name}}</span> </p> </div>`, // 使用OnPush模式只須要加上下面這段代碼 changeDetection: ChangeDetectionStrategy.OnPush }) export class TestComponent implements OnInit { @Input() user: User; constructor() { } ngOnInit() { } }
這時當咱們點擊改變屬性按鈕時test組件顯示的並不會變化,只有改變user得引用test組件顯示的纔會變化,以下圖所示
原本覺得這個問題沒什麼可寫的,直接解決好像就完事了,但沒想到寫着寫着感受能寫的愈來愈多,好比變動檢測的順序
,還有ExpressionChangedAfterItHasBeenCheckedError
都是應該知道的問題
,可是感受這些和主題又沒有什麼關係,想了想仍是算了。