ng-bind
单向数据绑定($scope -> view
),用于数据显示,简写形式是 {{}}
。git
1 |
<span ng-bind="val"></span> |
二者的区别在于页面没有加载完毕 {{val}}
会直接显示到页面,直到 Angular 渲染该绑定数据(这种行为有可能将 {{val}}
让用户看到);而 ng-bind
则是在 Angular 渲染完毕后将数据显示。angularjs
ng-model
是双向数据绑定($scope -> view
and view -> $scope
),用于绑定值会变化的表单元素等。github
1 |
<input type="text" ng-model="val" /> |
双向数据绑定意味着当 view
中有任何数据发生变化会自动地反馈到 scope
的数据上,当 scope
模型发生变化时,view
中的数据也会更新到最新的值。很显然,这须要一个监控。浏览器
事实上,AngularJS 确实在幕后为 scope
模型上设置了一个 监听队列,用来监听数据变化并更新view
。网络
每次绑定一个东西到 view
上时 AngularJS 就会往 $watch
队列里插入一条 $watch
,用来检测它监视的 model
里是否有变化的东西。app
当浏览器接收到能够被 angular context
处理的事件时,$digest
循环就会触发。$digest
会遍历全部的 $watch
。框架
好比进行一次 click
操做:函数
1 |
<button ng-click="val=val+1">increase 1</button> |
angular context
$digest
循环开始执行,查询每一个 $watch
是否变化$scope.val
的 $watch
报告了变化,它会强制再执行一次 $digest
循环。$digest
循环没有检测到变化。$scope.val
新值相应部分的 DOM
。$digest
循环不会只运行一次。在当前的一次循环结束后,它会再执行一次循环用来检查是否有models
发生了变化。ui
这就是脏检查(Dirty Checking
),它用来处理在 listener
函数被执行时可能引发的 model
变化。所以 $digest
循环会持续运行直到 model
再也不发生变化,或者 $digest
循环的次数达到了 10
次(超过 10
次后抛出一个异常,防止无限循环)。spa
当 $digest
循环结束时,DOM
相应地变化。
$apply
是 $scope
(或者是 direcvie
里的 link
函数中的 scope
)的一个函数,调用它会强制一次 $digest
循环(除非当前正在执行循环,这种状况下会抛出一个异常,这是咱们不须要在那里执行 $apply
的标志)。
$apply()
和 $digest()
有两个区别。
1) 最直接的差别是, $apply
能够带参数,它能够接受一个函数,而后在应用数据以后,调用这个函数。因此,通常在集成非 Angular 框架(好比jQuery)的代码时,能够把代码写在这个里面调用。
2) 当调用 $digest
的时候,只触发当前做用域和它的子做用域上的监控,可是当调用 $apply
的时候,会触发做用域树上的全部监控。
取决因而否在 Angular 上下文环境(angular context
)。
典型的须要调用 $apply()
方法的场景是:
1) 使用了 JavaScript 中的 setTimeout()
来更新一个 scope model
2) 用指令设置一个 DOM
事件 listener
而且在该 listener
中修改了一些 models
1 |
$scope.setMsg = function() { |
运行这个例子,会看到过了两秒钟以后,控制台确实会显示出已经更新的 model
,然而,view
并无更新。
在 $scope.getMessage
加入 $apply()
方法。
1 |
$scope.getMessage = function() { |
再运行就 OK 了。
不过,在 AngularJS 中应该尽可能使用 $timeout
Service 来代替 setTimeout()
,由于前者会帮你调用 $apply()
,让你不须要手动地调用它。
1 |
$timeout(function(){ |
实现一个 click
的指令,相似如下功能:
1 |
<button ng-click="val=val+1">increase 1</button> |
directive
的编写以下:
1 |
app.directive("inc", function() { |
跟场景一的结果同样,这个时候,点击按钮,界面上的数字并不会增长。但查看调试器,发现数据确实已经增长了。
在 scope.val++;
一行后面添加 scope.$apply();
或者 scope.$digest();
就 OK 了。
1) 无参
1 |
$scope.$apply() |
2) 有参
1 |
$scope.$apply(function(){ |
应该总使用接受一个 function
做为参数的 $apply()
方法。这是由于当传入一个 function
到$apply()
中的时候,这个 function
会被包装到一个 try…catch
块中,因此一旦有异常发生,该异常会被 $exceptionHandler service
处理。
想象一下若是有个 alert
框显示错误给用户,而后有个第三方的库进行一个网络调用而后失败了,若是不把它封装进 $apply
里面,Angular 永远不会知道失败了,alert
框就永远不会弹出来了。
经常使用的使用方式:
1 |
$scope.name = 'htf'; |
传入到 $watch()
中的第二个参数是一个回调函数,该函数在 name
的值发生变化的时候会被调用。
若是要监听的是一个对象,那还须要第三个参数:
1 |
$scope.data.name = 'htf'; |
表示比较的是对象的值而不是引用,若是不加第三个参数 true
,在 data.name
变化时,不会触发相应操做,由于引用的是同一引用。