AngularJs
為 scope
模型上設置了一個 監(jiān)聽隊列妙黍,用來監(jiān)聽數(shù)據(jù)變化并更新 view
冕茅。每次綁定一個東西到 view(html)
上時 AngularJs
就會往 $watch
隊列里插入一條 $watch
隘竭,用來檢測它監(jiān)視的 model
里是否有變化的東西。當瀏覽器接收到可以被 angular context
處理的事件時绘梦,$digest
循環(huán)就會觸發(fā)嘀掸。$digest
會遍歷所有的 $watch
。從而更新DOM
实幕。
$watch
這有點類似于我們的觀察者模式吝镣,在當前作用域$scope
下,我們創(chuàng)建一個監(jiān)控器$watchers
和一個監(jiān)聽器$watch
昆庇,$watchers
負責管理所有的 $watch
末贾,當我們每次綁定到UI
上的時候就自動創(chuàng)建一個$watch
,并把它放到 $watchers
整吆。
controller.js
app.controller('MainCtrl', function($scope) {
$scope.Hello = "Hello";
$scope.world = "World";
});
index.html
<div>{{Hello}}</div>
這里拱撵,即便我們在
$scope
上添加了兩個變量,但是只有一個綁定在了UI
上表蝙,因此在這里只生成了一個$watch
$digest
當瀏覽器接收到可以被angular context
處理的事件時拴测,$digest
循環(huán)就會觸發(fā)。$digest
將會遍歷我們的$watch
府蛇,如果$watch
沒有變化集索,這個循環(huán)檢測就將停止,如果有至少一個更新過汇跨,這個循環(huán)就會再次觸發(fā)务荆,直到所有的$watch
都沒有變化。這樣就能夠保證每個model
都已經不會再變化穷遂。這就是臟檢查(Dirty Checking
)機制
controller.js
app.controller('MainCtrl', function() {
$scope.name = "Foo";
$scope.changeFoo = function() {
$scope.name = "Bar";
}
});
index.js
<div>{{ name }}</div>
<button ng-click="changeFoo()">Change the name</button>
- 當我們按下按鈕
- 瀏覽器接收到一個事件函匕,進入
angular context
。 -
$digest
循環(huán)開始執(zhí)行蚪黑,查詢每個$watch
是否變化盅惜。 - 由于監(jiān)視
$scope.name
的$watch
報告了變化,它會強制再執(zhí)行一次$digest
循環(huán)祠锣。 - 新的
$digest
循環(huán)沒有檢測到變化酷窥。 - 更新與
$scope.name
新值相應部分的DOM
。
$apply
$apply
我們可以直接理解為刷新UI
伴网。如果當事件觸發(fā)時蓬推,你調用$apply
,它會進入angular context
澡腾,如果沒有調用就不會進入沸伏,之后的$digest
檢測機制就不會觸發(fā)
app.directive('clickable', function() {
return {
restrict: "E",
scope: {
foo: '='
},
template: '<ul style="background-color: lightblue"><li>{{foo}}</li></ul>',
link: function(scope, element, attrs) {
element.bind('click', function() {
scope.foo++;
console.log(scope.foo);
});
}
}
});
當我們調用
clickable
指令的時候糕珊,我們可以看到foo
的值增加了,但是界面上顯示的內容并沒有改變毅糟。$digest
臟檢測機制沒有觸發(fā)红选,檢測foo
的$watch
就沒有執(zhí)行。
$apply()方法的兩種形式
1) 無參
$scope.$apply();
element.bind('click', function() {
scope.foo++;
//if error
scope.$apply();
});
當我們使用這種形式的時候姆另,如果在scope.$apply之前程序發(fā)生異常喇肋,那scope.$apply沒有執(zhí)行,界面就不會更新
2) 有參
$scope.$apply(function(){
...
})
element.bind('click', function() {
scope.$apply(function() {
scope.foo++;
});
})
如果用這種形式迹辐,即使后面的發(fā)生異常蝶防,數(shù)據(jù)還是會更新。
在 AngularJS 中使用 $watch
常用的使用方式:
$scope.name = 'Hello';
$scope.$watch('name', function(newValue, oldValue) {
if (newValue === oldValue) { return; }
$scope.updated++;
});
傳入到
$watch()
中的第二個參數(shù)是一個回調函數(shù)明吩,該函數(shù)在name
的值發(fā)生變化的時候會被調用间学。
如果要監(jiān)聽的是一個對象,那還需要第三個參數(shù):
$scope.data.name = 'Hello';
$scope.$watch('data', function(newValue, oldValue) {
if (newValue === oldValue) { return; }
$scope.updated++;
}, true);
表示比較的是對象的值而不是引用印荔,如果不加第三個參數(shù)
true
低葫,在data.name
變化時,不會觸發(fā)相應操作仍律,因為引用的是同一引用嘿悬。