单向绑定(ng-bind) 和 双向绑定(ng-model) 的区别

ng-bind 单向数据绑定($scope -> view),用于数据显示,简写形式是 {{}}

1
<span ng-bind="val"></span>

两者的区别在于页面没有加载完毕 {{val}} 会直接显示到页面,直到 Angular 渲染该绑定数据(这种行为有可能将 {{val}} 让用户看到);而 ng-bind 则是在 Angular 渲染完毕后将数据显示。

ng-model 是双向数据绑定($scope -> view and view -> $scope),用于绑定值会变化的表单元素等。

1
<input type="text" ng-model="val" />

双向数据绑定的原理

双向数据绑定意味着当 view 中有任何数据发生变化会自动地反馈到 scope 的数据上,当 scope模型发生变化时,view 中的数据也会更新到最新的值。很显然,这需要一个监控。

事实上,AngularJS 确实在幕后为 scope 模型上设置了一个 监听队列,用来监听数据变化并更新view 。

每次绑定一个东西到 view 上时 AngularJS 就会往 $watch 队列里插入一条 $watch,用来检测它监视的 model 里是否有变化的东西。

当浏览器接收到可以被 angular context 处理的事件时,$digest 循环就会触发。$digest会遍历所有的 $watch 。

一次更新的操作(至少触发两次 $digest() 循环)

比如进行一次 click 操作:

1
<button ng-click="val=val+1">increase 1</button>
  • 按下按钮
  • 浏览器接收到一个事件,进入 angular context
  • $digest 循环开始执行,查询每个 $watch 是否变化
  • 由于监视 $scope.val 的 $watch 报告了变化,它会强制再执行一次 $digest 循环。
  • 新的 $digest 循环没有检测到变化。
  • 浏览器拿回控制权,更新与 $scope.val 新值相应部分的 DOM 。

$digest 循环会运行多少次?

$digest 循环不会只运行一次。在当前的一次循环结束后,它会再执行一次循环用来检查是否有models 发生了变化。

这就是脏检查(Dirty Checking),它用来处理在 listener 函数被执行时可能引起的 model变化。因此 $digest 循环会持续运行直到 model 不再发生变化,或者 $digest 循环的次数达到了 10 次(超过 10 次后抛出一个异常,防止无限循环)。

当 $digest 循环结束时,DOM 相应地变化。

$apply() 和 $digest() 的区别

$apply 是 $scope(或者是 direcvie 里的 link 函数中的 scope)的一个函数,调用它会强制一次 $digest 循环(除非当前正在执行循环,这种情况下会抛出一个异常,这是我们不需要在那里执行 $apply 的标志)。

$apply() 和 $digest() 有两个区别。

1) 最直接的差异是, $apply 可以带参数,它可以接受一个函数,然后在应用数据之后,调用这个函数。所以,一般在集成非 Angular 框架(比如jQuery)的代码时,可以把代码写在这个里面调用。

2) 当调用 $digest 的时候,只触发当前作用域和它的子作用域上的监控,但是当调用 $apply的时候,会触发作用域树上的所有监控。

什么时候手动调用 $apply() 方法?

取决于是否在 Angular 上下文环境(angular context)。

典型的需要调用 $apply() 方法的场景是:

1) 使用了 JavaScript 中的 setTimeout() 来更新一个 scope model

2) 用指令设置一个 DOM 事件 listener 并且在该 listener 中修改了一些 models

场景一

1
2
3
4
5
6
7
$scope.setMsg = function() {  
setTimeout(function() {
$scope.message = 'hello world';
console.log('message:' + $scope.message);
}, 2000);
}
$scope.setMsg();

运行这个例子,会看到过了两秒钟之后,控制台确实会显示出已经更新的 model,然而,view 并没有更新。

在 $scope.getMessage 加入 $apply() 方法。

1
2
3
4
5
6
7
8
$scope.getMessage = function() {  
setTimeout(function() {
$scope.$apply(function() {
$scope.message = 'hello world';
console.log('message:' + $scope.message);
});
}, 2000);
}

再运行就 OK 了。

不过,在 AngularJS 中应该尽量使用 $timeout Service 来代替 setTimeout(),因为前者会帮你调用 $apply(),让你不需要手动地调用它。

1
2
3
4
$timeout(function(){
$scope.message = 'hello world';
console.log('message:' + $scope.message);
}, 2000)

场景二

实现一个 click 的指令,类似以下功能:

1
<button ng-click="val=val+1">increase 1</button>

directive 的编写如下:

1
2
3
4
5
6
7
app.directive("inc", function() {
return function (scope, element, attr) {
element.on("click", function() {
scope.val++;
});
};
});

跟场景一的结果一样,这个时候,点击按钮,界面上的数字并不会增加。但查看调试器,发现数据确实已经增加了。

在 scope.val++; 一行后面添加 scope.$apply(); 或者 scope.$digest(); 就 OK 了。

$apply() 方法的两种形式

1) 无参

1
$scope.$apply()

2) 有参

1
2
3
$scope.$apply(function(){
...
})

应该总使用接受一个 function 作为参数的 $apply() 方法。这是因为当传入一个 function 到$apply() 中的时候,这个 function 会被包装到一个 try…catch 块中,所以一旦有异常发生,该异常会被 $exceptionHandler service 处理。

想象一下如果有个 alert 框显示错误给用户,然后有个第三方的库进行一个网络调用然后失败了,如果不把它封装进 $apply 里面,Angular 永远不会知道失败了,alert 框就永远不会弹出来了。

在 AngularJS 中使用 $watch

常用的使用方式:

1
2
3
4
5
$scope.name = 'htf';
$scope.$watch('name', function(newValue, oldValue) {
if (newValue === oldValue) { return; }
$scope.updated++;
});

传入到 $watch() 中的第二个参数是一个回调函数,该函数在 name 的值发生变化的时候会被调用。

如果要监听的是一个对象,那还需要第三个参数:

1
2
3
4
5
$scope.data.name = 'htf';
$scope.$watch('data', function(newValue, oldValue) {
if (newValue === oldValue) { return; }
$scope.updated++;
}, true);

表示比较的是对象的值而不是引用,如果不加第三个参数 true ,在 data.name 变化时,不会触发相应操作,因为引用的是同一引用。

参考

  1. 理解$watch ,$apply 和 $digest —- 理解数据绑定过程
  2. 理解Angular中的$apply()以及$digest()
  3. Angular沉思录(一)数据绑定
  4. 构建自己的AngularJS,第一部分:Scope和Digest

关于 AngularJS 的数据绑定的更多相关文章

  1. 10分钟学会AngularJS的数据绑定

     前言:为什么要用AngularJS?  相信用过.NetMVC的人都知道用rezor绑定数据是一件很爽的事情,C#代码直接在前台页面中输出.然后这种比较适用于同步请求.   当我们的项目离不开异步请 ...

  2. AngularJS双向数据绑定

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. 02、AngularJs的数据绑定

    我们知道,AngularJs中的数据绑定是双向绑定的,View的改变,会改变Model,Model的改变也会改变View中的值,废话不多说,我们直接上代码. <!DOCTYPE html> ...

  4. AngularJS笔记---数据绑定

    一.数据绑定 1.简单绑定 下面实现了一个简单的加法运算的绑定, A.ng-app:表示该div以内都在AngularJS的应用, 去掉ng-app="" 那么后面的绑定都将无效 ...

  5. AngularJS 的数据绑定

    单向绑定(ng-bind) 和 双向绑定(ng-model) 的区别 ng-bind 单向数据绑定($scope -> view),用于数据显示,简写形式是 {{}}. 1 <span n ...

  6. Vue、AngularJS 双向数据绑定解剖

    数据与视图的绑定与同步,最终体现在对数据的读写处理过程中,也就是 Object.defineProperty() 定义的数据 set.get 函数中.Vue 中对于的函数为 defineReactiv ...

  7. 关于AngularJs,数据绑定与自定义验证

    最近开始着手学起了Angular,抱着好奇的心情开始研究了起来.忽然发现angular可以巧妙而方便的进行数据的绑定验证啊什么的.(当然,我只是刚开始学,所有可能有更强大的功能,只是我还没有看到) 那 ...

  8. AngularJS入门心得2——何为双向数据绑定

    前言:谁说Test工作比较轻松,最近在熟悉几个case,差点没疯.最近又是断断续续的看我的AngularJS,总觉得自己还是没有入门,可能是自己欠前端的东西太多了,看不了几行代码就有几个常用函数不熟悉 ...

  9. AngularJS语法基础及数据绑定——详解各种数据绑定指令、属性应用

    AngularJS简单易学,但是功能强大.特别是在构建单页面应用方面效果显著.而 数据绑定 可以说是他被广泛使用的最主要的优点.他舍弃了对DOM的操作方式,一切都由AngularJS来自动更新视图,我 ...

随机推荐

  1. Maven:Maven 入门

    背景 几乎所有的主流平台都提供了依赖管理工具,如:.Net 的 Nuget.Ruby 的 Gem.Node 的 Npm等,今天简单的解释一下如何使用 Maven,以及最常见的问题. 下载 Maven ...

  2. Cohen-SutherLand算法(编码算法)

    转自:http://my.oschina.net/liqiong/blog/4921 Cohen-SutherLand算法(编码算法)   基本思想:对于每条线段P1P2,分为三种情况处理: (1)若 ...

  3. 7)Linux程序设计入门--网络编程

    )Linux程序设计入门--网络编程 Linux系统的一个主要特点是他的网络功能非常强大.随着网络的日益普及,基于网络的 应用也将越来越多. 在这个网络时代,掌握了Linux的网络编程技术,将令每一个 ...

  4. Qt 维护工具MaintenanceTool.exe 使用

    QT如何管理组件(解决“要继续此操作,至少需要一个有效且已启用的储存库”问题) 转载2017-10-26 01:48:46 标签:qt QT的组件管理软件并没有在开始菜单或者桌面添加快捷方式(5.9版 ...

  5. 对于Ian的访谈,不少关于GAN的内容

    文章链接如下: http://3g.163.com/dy/article/DD1GBSLF0511ABV6.html 里面提到胶囊网络,我找了这篇文章看了下: https://blog.csdn.ne ...

  6. Thinkphp学习笔记6-redirect 页面重定向

    ThinkPHP redirect 方法可以实现页面的重定向(跳转)功能.redirect 方法语法如下: $this->redirect(string url, array params, i ...

  7. Redis数据类型--List

    Redis列表是简单的字符串列表,依照插入顺序排序. 你能够加入一个元素到列表的头部(左边)或者尾部(右边) LPUSH 命令插入一个新的元素到头部, RPUSH插入一个新元素到尾部. 当一个这两个操 ...

  8. Unity3d使用json与javaserver通信

    Unity3d使用json能够借助LitJson 下载LitJson,复制到Unity3d工作文件夹下 于是能够在代码中实现了 以下发送请求到server并解析 System.Collections. ...

  9. angularjs中使用$q.defer

    方法method1和方法method2的区别,我还正在研究中...待添加 代码如下: <html ng-app="myApp"> <head> <ti ...

  10. 一些C++11语言新特性 - Range-Based for Loops

    1. Range-Based for Loops for ( decl : coll ) { statement} eg: , , , , , , , } ) { std::cout << ...