1. 程式人生 > >AngularJS的資料雙向繫結是怎麼實現的?

AngularJS的資料雙向繫結是怎麼實現的?

單向繫結(ng-bind) 和 雙向繫結(ng-model) 的區別:
ng-bind 單向資料繫結($scope -> view),用於資料顯示,簡寫形式是 {{}}
<span ng-bind="val"></span>
兩者的區別在於頁面沒有載入完畢 {{val}}會直接顯示到頁面,直到 Angular 渲染該繫結資料(這種行為有可能將 {{val}}讓使用者看到);而 ng-bind則是在 Angular 渲染完畢後將資料顯示。ng-model是雙向資料繫結($scope -> view and view ->$scope),用於繫結值會變化的表單元素等。<input type="text" ng-model="val" />

有三個概念:

  • $digest():髒值檢查迴圈
  • $watch:新增監聽
  • $apply:提供上下文執行表示式

雙向資料繫結(bi-directional)意味著如果檢視改變了某個值,資料模型會通過髒檢查觀察到這個變化,而如果資料模型改變了某個值,檢視也會依據變化重新渲染。

當你寫下表達式如{{ aModel }}時,AngularJS在幕後會為你在scope模型上設定一個watcher,它用來在資料發生變化的時候更新view。這裡的watcher和你會在AngularJS中設定的watcher是一樣的

對於所有繫結給同一$scope元素的UI物件,只會新增一個$watch到$watch列表中(一個數據一個$watcher,物件會有一個,裡面的值還會有,陣列中每個物件都有一個 )。這些$watch列表會在$digest迴圈中通過一個叫做“髒值檢查”的程式解析

  • 假設你在一個ng-click指令對應的handler函式中更改了scope中的一條資料
  • 此時AngularJS會自動地通過呼叫$digest()來觸發一輪$digest迴圈。
  • 當$digest迴圈開始後,它會觸發每個watcher。
  • 這些watchers會檢查scope中的當前model值是否和上一次計算得到的model值不同。
  • 如果不同,那麼對應的回撥函式會被執行。呼叫該函式的結果,就是view中的表示式內容(譯註:諸如{{ aModel }})會被更新。

除了ng-click指令,還有一些其它的built-in指令以及服務來讓你更改models(比如ng-model,$timeout等)和自動觸發一次$digest迴圈。如下:

談起angular的髒檢查機制(dirty-checking), 常見的誤解就是認為: ng是定時輪詢去檢查model是否變更。 其實,ng只有在指定事件觸發後,才進入$digest cycle:

  • DOM事件,譬如使用者輸入文字,點選按鈕等。(ng-click)
  • XHR響應事件 ($http)
  • 瀏覽器Location變更事件 ($location)
  • Timer事件($timeout, $interval)
  • 執行$digest()或$apply()
    上述事件發生->$digest()迴圈->觸發每個watcher->watcher檢查scope中的當前model值和上一次計算得到的model值是否不同->如果不同,那麼$watch()對應的回撥函式會被執行->呼叫該函式的結果,就是view中的表示式內容(譯註:諸如{{ aModel }})會被更新

angularJS並不直接呼叫$digest(),而是呼叫$scope.$apply(),後者會呼叫$rootScope.$digest()。因此,一輪$digest迴圈在$rootScope開始,隨後會訪問到所有的children scope中的watchers