一 简介
AngularJS提供了一个非常酷的特性叫做双向数据绑定(Two-way Data Binding),这个特性大大简化了我们的代码编写方式。数据绑定意味着当View中有任何数据发生了变化,那么这个变化也会自动地反馈到scope的数据上,也即意味着scope模型会自动地更新。类似地,当scope模型发生变化时,view中的数据也会更新到最新的值。那么AngularJS是如何做到这一点的呢?当你写下表达式如{{ aModel }}时,AngularJS在幕后会为你在scope模型上设置一个watcher,它用来在数据发生变化的时候更新view。
二 $watch
1.什么是$watch
$scope对象上的$watch方法会给Angular事件循环内的每个$digest调用装配一个脏值检查,如果在表达式上检测到变化,Angular总是会返回$digest循环。
也就是说,$watch代表的就是对数据源的监听,当数据源发生变化,就会触发第二个参数的回调函数。
2.使用
$watch函数本身接受两个必要参数和一个可选的参数:
$scope.$watch(‘aModel’, function(newValue, oldValue) {
//update the DOM with newValue
},true);
第一个参数:可以是一个作用域对象的属性,或者是一个函数,在$digest循环中的每个$digest调用都会涉及到它。如果是一个字符串,Angular会在$scope上下文中对它求值。
第二个参数:作为回调的监听器函数,它智慧在第一个参数的当前值与先前值不相等时调用。
第三个参数:true/false,默认为false,主要用于第一个参数为引用型的情况下。
3.举例:
<body>
<input ng-model=‘name‘ type=‘text‘/>
<div>change count: {{count}}</div>
<script>
angular.module(‘myApp‘,[])
.run([‘$rootScope‘,function($rootScope){
$rootScope.count = 0;
$rootScope.name = ‘hcc‘;
$rootScope.$watch(‘name‘,function(){
$rootScope.count++;
})
}]);
</script>
</body>
用$watch来对$rootScope中的name进行监视,并在它发生变化的时候将$rootScope中的count属性增加1。因此,每当我们对name进行一次修改时,下面显示的count数字就会增加1。
然而,我们在实际运用中常常不只是对一个原始类型的属性进行监视,还可能对集合进行监视。对于原始类型,如果我们使用了一个赋值操作,则这个原始类型变量会“真正的”被进行一次复制,然而对于引用类型,在进行赋值时,仅仅是将赋值的变量指向了这个引用类型。因此如果要对一个引用类型,尤其是在实际运用中常见的对象数组进行监视时,情况就不一样了。
<body>
<div hg-repeat=‘item in items‘>
<input ng-model=‘item.a‘/><span>{{item.a}}</span>
</div>
<div>change count: {{count}}</div>
<script>
angular.module(‘myApp‘,[])
.run([‘$rootScope‘,function($rootScope){
$rootScope.count = 0;
$rootScope.items = [
{ "a": 1 },
{ "a": 2 },
{ "a": 3 },
{ "a": 4 }
]
$rootScope.$watch(‘items‘,function(){
$rootScope.count++;
},true)
}]);
</script>
</body>
在angular 1.1.4版本之后,添加了一个$watchCollection()方法来针对数组(也就是集合)进行监视,它的性能介于全等监视和引用监视二者之间,即它并不会对数组中每一项的属性进行监视,但是可以对数组的项目的增减做出反应。
在这里只需将$rootScope.$watch改成$rootScope.$watchCollection即可:
$rootScope.$watchCollection(‘items‘,function() {
$rootScope.count++;
})
对集合的操作,推荐使用这种方式。
三 $digest和$apply
1.在调用了$scope.$digest()后,$digest循环就开始了。假设你在一个ng-click指令对应的handler函数中更改了scope中的一条数据,此时AngularJS会自动地通过调用$digest()来触发一轮$digest循环。当$digest循环开始后,它会触发每个watcher。这些watchers会检查scope中的当前model值是否和上一次计算得到的model值不同。如果不同,那么对应的回调函数会被执行。调用该函数的结果,就是view中的表达式内容会被更新。
AngularJS并不直接调用$digest(),而是调用$scope.$apply(),后者会调用$rootScope.$digest()。因此,一轮$digest循环在$rootScope开始,随后会访问到所有的children scope中的watchers。
正常情况下,在angular上下文中,修改数据源就会自动触发。$apply只是把$digest做了一次封装,来提供手动触发,那么为什么需要手动触发呢。因为如果是不在angular上下文的情况下,如浏览器DOM事件,setTimeout执行,这种情况下,angular无法获取到事件,所以,通过apply来手动触发一下,在apply的参数中去修改数据源。
2.举例:
<body ng-app=“myApp”>
<div ng-controller=“MessageController”>
Delayed Message: {{message}}
</div>
</body>
angular.module(‘myApp’,[]).controller(‘MessageController’, function($scope) {
$scope.getMessage = function() {
setTimeout(function() {
$scope.message = ‘Fetched after 3 seconds';
console.log(‘message:’+$scope.message);
}, 2000);
}

$scope.getMessage();

});
通过运行这个例子,你会看到过了两秒钟之后,控制台确实会显示出已经更新的model,然而,view并没有更新。原因也许你已经知道了,就是我们忘了调用$apply()方法。因此,我们需要修改getMessage()。
angular.module(‘myApp’,[]).controller(‘MessageController’, function($scope) {
$scope.getMessage = function() {
setTimeout(function() {
$scope.$apply(function() {
//wrapped this within $apply
$scope.message = ‘Fetched after 3 seconds';
console.log(‘message:’ + $scope.message);
});
}, 2000);
}

$scope.getMessage();

});

angularJS $watch $digest $apply的更多相关文章

  1. 理解Angular中的$apply()以及$digest()

    $apply()和$digest()在AngularJS中是两个核心概念,但是有时候它们又让人困惑.而为了了解AngularJS的工作方式,首先需要了解$apply()和$digest()是如何工作的 ...

  2. 深入理解Angular中的$Apply()以及$Digest()

    $apply()和$digest()在AngularJS中是两个核心概念,但是有时候它们又让人困惑.而为了了解AngularJS的工作方式,首先需要了解$apply()和$digest()是如何工作的 ...

  3. angularJS中的$apply(),$digest(),$watch()

    $apply()和$digest()在AngularJS中是两个核心概念,但是有时候它们又让人困惑.而为了了解AngularJS的工作方式,首先需要了解$apply()和$digest()是如何工作的 ...

  4. $watch How the $apply Runs a $digest

    作者:junyuecao | 发表于 8-8 13:39 | 最后更新时间:8-9 02:34 原文地址:http://angular-tips.com/blog/2013/08/watch-how- ...

  5. $apply() $digest()

    理解Angular中的$apply()以及$digest() <!DOCTYPE html> <html> <head> <meta charset=&quo ...

  6. angularjs现学现记之—$apply()和$digest()

    angularjs的双向数据绑定是个重要的特性,它让我们的代码简洁了许多,然而它又是如何知道数据发生了变化并改变页面的呢.最近看了一篇介绍觉得十分有用 首先,在angularjs中是有$watch事件 ...

  7. Angular DirtyChecking(脏值检查) $watch, $apply, $digest

    Dirty Checking (脏值检查) Digest cycle and $scope Digest cycle and $scope First and foremost, AngularJS ...

  8. --@angularjs--理解Angular中的$apply()以及$digest()

    $apply() 和 $digest() 在 AngularJS 中是两个核心概念,但是有时候它们又让人困惑.而为了了解 AngularJS 的工作方式,首先需要了解 $apply() 和 $dige ...

  9. (网页)理解Angular中的$apply()以及$digest()

    转自CSDN: 工作有问题上CSDN上转转. $apply()和$digest()在AngularJS中是两个核心概念,但是有时候它们又让人困惑.而为了了解AngularJS的工作方式,首先需要了解$ ...

  10. Angular1.x DirtyChecking(脏值检查) $watch, $apply, $digest

    Dirty Checking (脏值检查) Digest cycle and $scope Digest cycle and $scope First and foremost, AngularJS ...

随机推荐

  1. IOS 多线程,线程同步的三种方式

    本文主要是讲述 IOS 多线程,线程同步的三种方式,更多IOS技术知识,请登陆疯狂软件教育官网. 一般情况下我们使用线程,在多个线程共同访问同一块资源.为保护线程资源的安全和线程访问的正确性. 在IO ...

  2. 极端气候频现 五款开发天气预报应用的API

    http://www.csdn.net/article/2014-02-07/2818322-weather-forecast-api-for-developing-apps

  3. 复制JAVABEAN中的属性到另外一个JAVABEAN中

    下午写了一个属性复制方法,记录如下: class POUtil{ /** * * Function : 将一个source中的属性到复制到dest * @author : Liaokailin * C ...

  4. php学习小技巧

    1.print_r可打印数组 <?php echo '<p class="ajax">This paragraph was loaded with AJAX.&l ...

  5. 『重构--改善既有代码的设计』读书笔记----Introduce Foreign Method

    当你无法获得一个类的源代码或者没有权限去修改这个类的时候,你对于这种为你服务的类,你可能会出现需要别的需求的时候,比如一个Date类,你需要能够让他本身直接返回出他的后一天的对象,但他没有,这个时候你 ...

  6. linux系统删除空间后系统分区空间仍不释放问题

    总结的原因: 1.删除文件文件后没有清空回收站; 2.删除的文件不在系统分区,在其他分区上; 3.删除的文件被保留在了/tmp分区下,而/tmp分区不是独立的分区,是在根分区/的基础上划分出来的分区; ...

  7. JavaScript解析机制

    JavaScript是一种解释型语言,按照<script>块儿来预编译和执行. JavaScript解释器在预编译阶段,先预声明变量,再预声明函数.在执行阶段,进行变量赋值,和函数执行. ...

  8. vs 2015 菜单重复的问题解决方法

    打开 “运行” 输入 D:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe /resetuserdata ...

  9. Object-C非正式协议与正式协议的区别

    Object-C非正式协议与正式协议的区别 这两个概念困扰我很久了,一直都很像搞清楚到非正式协议和正式协议有什么区别和联系,下面结合网上的资料和自己的看法谈谈这个问题. 一.非正式协议 显然这个名词是 ...

  10. 【MySQL】SQL语法,between and 使用注意事项

    业务代码中有条查询学生姓名的sql: select stu_name from stu_info where stu_id between id_1 and id_2; 估计当时一时恍惚,拼接sql时 ...