Angular開發實務(五):深入解析變化監測
什麼是變化監測
在使用Angular 進行開發中,我們常用到Angular 中的綁定-模型到視圖的輸入綁定、視圖到模型的輸出綁定以及視圖與模型的雙向綁定。而這些綁定的數值之所以能在視圖與模型之間保持同步,正是得益於Angular中的變化檢測。
簡單來說,變化偵測就是Angular 用來偵測視圖與模型之間綁定的值是否發生了改變,當偵測到模型中綁定的值改變時,則同步到視圖上,反之,當偵測到視圖上綁定的值發生改變時,則回呼對應的綁定函數。
變更監控的源頭
變更監測的關鍵在於如何最小粒度地監測到綁定的值是否發生了改變,那麼在什麼情況下會導致這些綁定的值發生變化呢?我們可以看一下我們常用的幾個場景:
Events: click/hover/...
@Component({ selector: 'demo-component', template: ` <h1>{{name}}</h1> <button (click)="changeName()">change name</button> ` }) export class DemoComponent { name: string = 'Tom'; changeName() { this.name = 'Jerry'; } }
我們在模板中透過插值表達式綁定了 name 屬性。當點擊change name按鈕
時,改變了 name 屬性的值,這時模板視圖顯示內容也改變了。
XHR/webSocket
@Component({ selector: 'demo-component', template: ` <h1>{{name}}</h1> ` }) export class DemoComponent implements OnInit { name: string = 'Tom'; constructor(public http: HttpClient) {} ngOnInit() { // 假设有这个./getNewName请求,返回一个新值'Jerry' this.http.get('./getNewName').subscribe((data: string) => { this.name = data; }); } }
我們在這個組件的ngOnInit 函數裡向伺服器端發送了一個Ajax 請求,當這個請求返回結果時,同樣會改變當前模板視圖上綁定的name 屬性的值。
Times: setTimeout/requestAnimationFrame
@Component({ selector: 'demo-component', template: ` <h1>{{name}}</h1> ` }) export class DemoComponent implements OnInit { name: string = 'Tom'; constructor() {} ngOnInit() { // 假设有这个./getNewName请求,返回一个新值'Jerry' setTimeout(() => { this.name = 'Jerry'; }, 1000); } }
我們在這個元件的ngOnInit函數裡透過設定一個定時任務,當定時任務執行時,同樣會改變當前視圖上綁定的name屬性的值。
總結
其實,我們不難發現上述三種情況都有一個共同點,就是這些導致綁定值改變的事件都是非同步發生的。
Angular並不是捕捉物件的變動,它採用的是在適當的時機去檢驗物件的值是否被改動,這個時機就是這些非同步事件的發生。
這個時機是由NgZone 這個服務去掌控的,它獲取到了整個應用的執行上下文,能夠對相關的非同步事件發生、完成或異常等進行捕獲,然後驅動Angular的變化監測機制執行。
變化監測的處理機制
透過上面的介紹,我們大致明白了變化檢測是如何被觸發的,那麼Angular 中的變化監測是如何執行的呢?
首先我們需要知道的是,對於每一個元件,都有一個對應的變化監測器;即每一個Component 都對應有一個changeDetector
,我們可以在Component 中透過依賴注入來取得到changeDetector
。
而我們的多個Component 是一個樹狀結構的組織,由於一個Component 對應一個changeDetector
,那麼changeDetector
之間同樣是一個樹狀結構的組織。
最後我們要記住的一點是,每次變化監測都是從 Component 樹根開始的。
舉例
子元件:
@Component({ selector: 'demo-child', template: ` <h1>{{title}}</h1> <p>{{paramOne}}</p> <p>{{paramTwo}}</p> ` }) export class DemoChildComponent { title: string = '子组件标题'; @Input() paramOne: any; // 输入属性1 @Input() paramTwo: any; // 输入属性2 }
父元件:
@Component({ selector: 'demo-parent', template: ` <h1>{{title}}</h1> <demo-child [paramOne]='paramOneVal' [paramTwo]='paramTwoVal'></demo-child> <button (click)="changeVal()">change name</button> ` }) export class DemoParentComponent { title: string = '父组件标题'; paramOneVal: any = '传递给paramOne的数据'; paramTwoVal: any = '传递给paramTwo的数据'; changeVal() { this.paramOneVal = '改变之后的传递给paramOne的数据'; } }
上面的程式碼中,DemoParentComponent 透過
當我們點擊DemoParentComponent 的button 時,會回調到changeVal 方法,然後會觸發變化監測的執行,變化監測流程如下:
首先變更偵測從DemoParentComponent開始:
偵測title 值是否發生了變化:沒有發生變化
偵測paramOneVal 值是否發生了變化:發生了變化(點擊按鈕呼叫changeVal()方法改變的)
檢測paramTwoVal 值是否發生了變化:沒有變化
然後變化檢測進入到葉子節點DemoChildComponent:
偵測title 值是否發生了改變:沒有發生變化
偵測paramOne 是否發生了變化:發生了改變(由於父元件的屬性paramOneVal發生了改變)
- ##檢測paramTwo 是否發生了改變:沒有改變 ##最後,因為DemoChildComponent 再也沒有了葉子節點,所以變化監測將更新DOM,同步視圖與模型之間的變化。
變化監測策略
學習了變化監測的處理機制之後,你可能會想,這機制未免也有點太簡單粗暴了吧,假如我的應用中有成百上千個Component,隨便一個Component 觸發了監測,那麼都需要從根節點到葉節點重新偵測一次。
別急,Angular 的開發團隊已經考慮到了這個問題,上述的偵測機制只是一種預設的偵測機制,Angular 也提供一個OnPush 的偵測機制(設定元資料屬性changeDetection: ChangeDetectionStrategy.OnPush )。
OnPush 与 Default 之间的差别:当检测到与子组件输入绑定的值没有发生改变时,变化检测就不会深入到子组件中去。
变化监测类 - ChangeDetectorRef
上面说到我们可以修改组件元数据属性 changeDetection 来修改组件的变化监测策略(ChangeDetectionStrategy.Default 或 ChangeDetectionStrategy.OnPush),除了这个,我们还可以使用 ChangeDetectorRef 来更加灵活的控制组件的变化监测。
Angular 在整个运行期间都会为每一个组件创建 ChangeDetectorRef 的实例,该实例提供了相关方法来手动管理变化监测。有了这个类,我们自己就可以自定义组件的变化监测策略了,如停止/启用变化监测或者按指定路径变化监测等等。
相关方法如下:
markForCheck():把根组件到该组件之间的这条路径标记起来,通知Angular在下次触发变化监测时必须检查这条路径上的组件。
detach():从变化监测树中分离变化监测器,该组件的变化监测器将不再执行变化监测,除非再次手动执行reattach()方法。
reattach():把分离的变化监测器重新安装上,使得该组件及其子组件都能执行变化监测。
detectChanges():手动触发执行该组件到各个子组件的一次变化监测。
使用方法也很简单,直接在组件中注入即可:
@Component({ selector: 'demo-parent', template: ` <h1>{{title}}</h1> ` }) export class DemoParentComponent implements OnInit { title: string = '组件标题'; constructor(public cdRef: ChangeDetectorRef) {} ngOnInit() { this.cdRef.detach(); // 停止组件的变化监测,看需求使用不同的方法 } }
相关推荐:
以上是Angular開發實務(五):深入解析變化監測的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

深入解析HTTP狀態碼460的作用和應用場景HTTP狀態碼是Web開發中非常重要的一部分,用來表示客戶端和伺服器之間的通訊狀態。其中,HTTP狀態碼460是較為特殊的狀態碼,本文將深入解析它的作用與應用場景。 HTTP狀態碼460的定義HTTP狀態碼460的具體定義是"ClientClosedRequest",意為客戶端關閉請求。此狀態碼主要用於表示

iBatis和MyBatis:區別和優勢解析導語:在Java開發中,持久化是一個常見的需求,而iBatis和MyBatis是兩個廣泛使用的持久化框架。雖然它們有很多相似之處,但也有一些關鍵的區別和優勢。本文將透過詳細分析這兩個框架的特性、用法和範例程式碼,為讀者提供更全面的了解。一、iBatis特性:iBatis是目前較老舊的持久化框架,它使用SQL映射文件

Angular.js是一種可自由存取的JavaScript平台,用於建立動態應用程式。它允許您透過擴展HTML的語法作為模板語言,以快速、清晰地表示應用程式的各個方面。 Angular.js提供了一系列工具,可協助您編寫、更新和測試程式碼。此外,它還提供了許多功能,如路由和表單管理。本指南將討論在Ubuntu24上安裝Angular的方法。首先,您需要安裝Node.js。 Node.js是一個基於ChromeV8引擎的JavaScript運行環境,可讓您在伺服器端執行JavaScript程式碼。要在Ub

Oracle錯誤3114詳解:如何快速解決,需要具體程式碼範例在Oracle資料庫開發與管理過程中,我們常常會遇到各種各樣的錯誤,其中錯誤3114是比較常見的一個問題。錯誤3114通常表示資料庫連線出現問題,可能是網路故障、資料庫服務停止、或連接字串設定不正確等原因導致的。本文將詳細解釋錯誤3114的產生原因,以及如何快速解決這個問題,並附上具體的程式碼

Wormhole在區塊鏈互通性方面處於領先地位,專注於創建有彈性、面向未來的去中心化系統,優先考慮所有權、控制權和無需許可的創新。這個願景的基礎是對技術專業知識、道德原則和社群一致性的承諾,旨在以簡單、清晰和廣泛的多鏈解決方案套件重新定義互通性格局。隨著零知識證明、擴容方案和功能豐富的Token標準的興起,區塊鏈變得更加強大,而互通性也變得越來越重要。在這個不斷創新的應用程式環境中,新穎的治理系統和實用功能為整個網路的資產帶來了前所未有的機會。協議建構者現在正在努力思考如何在這個新興的多鏈

Angular框架中元件的預設顯示行為不是區塊級元素。這種設計選擇促進了元件樣式的封裝,並鼓勵開發人員有意識地定義每個元件的顯示方式。透過明確設定CSS屬性 display,Angular組件的顯示可以完全控制,從而實現所需的佈局和響應能力。

【PHP中點的意義和用法解析】在PHP中,中點(.)是常用的運算符,用來連接兩個字串或物件的屬性或方法。在本文中,我們將深入探討PHP中點的意義和用法,並透過具體的程式碼範例加以說明。 1.連接字串中點運算子.在PHP中最常見的用法是連接兩個字串。透過將.放置在兩個字串之間,可以將它們拼接在一起,形成一個新的字串。 $string1=&qu

由於篇幅限制,以下是一個簡短的文章:Apache2是常用的Web伺服器軟體,而PHP是廣泛使用的伺服器端腳本語言。在建置網站過程中,有時會遇到Apache2無法正確解析PHP檔案的問題,導致PHP程式碼無法執行。這種問題通常是因為Apache2沒有正確配置PHP模組,或是PHP模組與Apache2的版本不相容所導致的。解決這個問題的方法一般有兩種,一種是
