要说明 $watch()、$digest() 和 $apply() 的工作原理,请看以下示例:
<div ng-controller="myController">
{{data.time}}
<br/>
<button ng-click="updateTime()">update time - ng-click</button>
<button id="updateTimeButton" >update time</button>
</div>
<script>
var module = angular.module("myapp", []);
var myController1 = module.controller("myController", function($scope) {
$scope.data = { time : new Date() };
$scope.updateTime = function() {
$scope.data.time = new Date();
}
document.getElementById("updateTimeButton")
.addEventListener('click', function() {
console.log("update time clicked");
$scope.data.time = new Date();
});
});
</script>
此示例将 $scope.data.time 变量绑定到插值指令,该指令将变量值合并到 HTML 页面中。此绑定在 $scope.data.time 变量内部创建一个监视。
该示例还包含两个按钮。第一个按钮附加了一个 ng-click 侦听器。单击该按钮时,会调用 $scope.updateTime() 函数,然后 AngularJS 会调用 $scope.$digest() 以便更新数据绑定。
第二个按钮从控制器函数内部获得一个附加的标准 JavaScript 事件侦听器。单击第二个按钮时,将执行侦听器函数。如您所见,两个按钮的侦听器函数几乎相同,但是当调用第二个按钮的侦听器函数时,数据绑定不会更新。那是因为在执行第二个按钮的事件侦听器之后没有调用 $scope.$digest()。因此,如果您单击第二个按钮,则 $scope.data.time 变量中的时间会更新,但不会显示新时间。
为了解决这个问题,我们可以在按钮事件监听器的最后一行添加一个 $scope.$digest() 调用,如下所示:
document.getElementById("updateTimeButton")
.addEventListener('click', function() {
console.log("update time clicked");
$scope.data.time = new Date();
$scope.$digest();
});
除了在按钮侦听器函数中调用 $digest() 之外,您还可以像这样使用 $apply() 函数:
document.getElementById("updateTimeButton")
.addEventListener('click', function() {
$scope.$apply(function() {
console.log("update time clicked");
$scope.data.time = new Date();
});
});
注意 $scope.$apply() 函数是如何从按钮事件监听器内部调用的,以及 $scope.data.time 变量的更新是如何在作为参数传递给 $apply() 的函数内部执行的功能。当 $apply() 函数调用完成时,AngularJS 在内部调用 $digest(),所以所有的数据绑定都会更新。