Angular開發實踐(五):深入解析變化監測

来源:https://www.cnblogs.com/laixiangran/archive/2018/03/26/8653881.html
-Advertisement-
Play Games

在使用 Angular 進行開發中,我們常用到 Angular 中的綁定——模型到視圖的輸入綁定、視圖到模型的輸出綁定以及視圖與模型的雙向綁定。而這些綁定的值之所以能在視圖與模型之間保持同步,正是得益於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 通過 標簽嵌入了 DemoChildComponent,從樹狀結構上來說,DemoParentComponent 是 DemoChildComponent 的根節點,而 DemoChildComponent 是 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(); // 停止組件的變化監測,看需求使用不同的方法
    }
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這裡說一個官方推薦的寫法: 根據上面的代碼,一旦綁定activity,也自然會註冊介面,所以只要在activity中實現介面便可以了。 ...
  • 動畫 1.常規動畫屬性設置(可以同時選擇多個進行設置) UIViewAnimationOptionLayoutSubviews:動畫過程中保證子視圖跟隨運動。**提交動畫的時候佈局子控制項,表示子控制項將和父控制項一同動畫。** UIViewAnimationOptionAllowUserInteract ...
  • 先看看效果圖 一個消息列表,然後點擊item後會刷新時間,點擊置頂後也會刷新時間,置頂規則就是根據兩個欄位來排序 如果是置頂狀態,top為1,然後每次操作都會刷新 time的時間,time是存的時間戳,先看看實體類 package com.fragmentapp.home.bean; import ...
  • 最近在項目中經常用到UITableView中的cell中帶有UITextField或UITextView的情況,然後在這種場景下,當我們點擊屏幕較下方的cell進行編輯時,這時候鍵盤彈出來會出現遮擋待輸入的cell,導致我們無法很方便地查看到我們輸入的內容,這樣的體驗是非常不好的。這個問題在之前我們 ...
  • HTML5 是下一代的 HTML。 什麼是 HTML5? HTML5 將成為 HTML、XHTML 以及 HTML DOM 的新標準。 HTML 的上一個版本誕生於 1999 年。自從那以後,Web 世界已經經歷了巨變。 HTML5 仍處於完善之中。然而,大部分現代瀏覽器已經具備了某些 HTML5 ...
  • 剛纔被博客園官方移出首頁,不服,再發一遍,絕對原創,手打,思路清晰。 首先說一下,我不是阿裡的人,也沒去阿裡面試過,這是某微信群里的一個小伙伴給的,我現在的能力達不到阿裡的要求。不過人沒夢想還不如鹹魚,有能力的話還是想去嘗試一下。本文如有不足,請勿嘲諷,指出不足即可,謝謝。碼字不易,且看且珍惜,轉載 ...
  • 一、jQuery的封裝擴展 1、jQuery中extend方法使用 (掛在到jQuery和jQuery.fn兩對象身上的使用) 1.1、官方文檔定義: jQuery.extend Merge the contents of two or more objects together into the ...
  • 一、常見的web安全及防護原理 1.sql註入原理 就是通過把sql命令插入到web表單遞交或輸入功能變數名稱或頁面請求的查詢字元串,最終達到欺騙伺服器執行惡意的SQL命令。 防護,總的來說有以下幾點: 1、永遠不要信任用戶的輸入,要對用戶的輸入進行校驗,可以通過正則表達式,或限制長度,對單引號雙“--”進 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...