Angular.js 中的特性,雙向綁定.
多麼神奇的功能,讓視圖的改變直接反應到數據中,數據的改變又實時的通知到視圖,如何做到的?
這要歸功於 scope 下面3個重要的方法:
$watch
$digest
$apply
他們的區別是什麼,我們來介紹下:
$watch
這是一個監聽 scope 上數據的監聽器
方法說明:
$scope.$watch('參數',function(newValue,oldValue){ //邏輯處理 })
上面我們就是創建了一個監聽器.
‘參數' 就是$scope對象下的一個對象(或者一個對象的屬性),注意,這裡是字符串形式.
假如你要監聽 $scope.name 屬性.
$scope.$watch('name',function(newValue,oldValue){ //邏輯處理 })
如上代碼, ‘name' 需要引號
參數後面跟著回調函數,回調函數參數返回了被監聽 屬性,變化後的新值,以前變化前的舊值.
$digest
他負責檢查 scope 中的數據是否發生了變化,如果某個屬性有變化,馬上會通知此屬性的監聽器 ($watch 注冊的監聽器),觸發監聽器,執行回調函數.
$apply
這個方法和 $digest 很相似, $digest 檢查scope 中的所有數據
$apply 相當於檢查 rootScope 中的所有數據,他會從父級到子級來檢查所有數據
$apply() == $rootScope.$digest()
$apply() 方法有兩種形式.
第一種 接受一個 function作為參數.
這樣觸發 $digest 函數並且執行一次 參數中的 function
第二種 不接受任何參數.
這樣只是觸發一輪 $digest 父級到子級的循環
Angular.js 中一班不會直接調用 $digest ,而是用 $scope.$apply() 來代替
我沒有設定監視器,為什麼視圖和數據可以雙向綁定
比如一個文本框 ng-model="name"
這時其實 $scope 對象下已經有了一個屬性 name 來對應和 上面的視圖進行雙向綁定
如何實現的?
其實,當我們定義 ng-model="name" 或者 ng-bind="name" 或者 {{name}}
這時 angular.js 會在 $scope 模型上自動為 “name” 屬性設置一個監聽器:
$scope.$watch('name', function(newValue, oldValue) { //監聽 name 屬性的變化 });
原來這裡 angular.js 幫我們自動創建了一個監聽器,所以此屬性和 $scope.name 數據才會實時的雙向綁定.
當然,有時候你也會發現明明數據變化了.但是UI 沒有刷新,是雙向綁定失效了嗎?
沒有
只是在 $scope 模型遍歷 digest 循環時,你的數據還沒有返回來,
比如異步調用方法,callbac 返回的數據
比如你在 setTimeout 設置了定時觸發函數,然後修改模型數據
總之,是錯過了 $scope 模型的 digest 循環,導致模型沒有通知UI去根據新數據刷新.
遇到這樣的問題怎麼辦?
我們只好自己去手動調用 digest來循環檢查一次數據.實現雙向綁定
上面我們已經說過,通常不要去直接調用 digest 方法,而是手動調用 $apply 方法,間接實現觸發 $digest 循環.
如下:
setTimeout(function() { $scope.name= '一介布衣'; $scope.$apply(); }, 2000);
問題來了,上面時候該去手動調用 apply 方法
目前為止, angular.js 為一部分指令和服務自動實現了 $apply() 方法.
例如, ng-click ,ng-model ,$timeout服務,$http服務 等
調用後,angular.js 會自動幫我們調用 $apply() 來實現數據雙向綁定.