2015-05-24 49 views
8

AngularJS允许您实现双向数据绑定。但是,有趣的部分是它如何检测模型更改?该模型通常是一个普通的对象,如下面的代码。我们可以更改$scope.user的名称属性,但AngularJS如何检测模型更改? AngularJS会枚举$scope对象的所有属性吗?AngularJS如何实现其双向数据绑定机制?

angular.module('myApp', []) 
     .controller('BusinessCardController', function($scope){ 
     $scope.user = { 
      name: 'Tanay Pant' 
     } 
     }); 

<input type="text" ng-model="user.name" placeholder="Full Name" /> 

回答

10

有一个摘要循环,范围检查所有$ watch表达式并将它们与先前的值进行比较。它会查看对象模型的变化,如果旧值与新值不同,AngularJS会更新适当的位置,也就是脏检查。

为了执行摘要循环$apply(fn)必须运行,这是您如何从JavaScript进入Angular世界。如何$apply(fn)被调用(取自AngularJs integration with browser):

  1. 浏览器的事件循环等待一个事件的到来。事件是用户交互,计时器事件或网络事件(来自服务器的响应)。
  2. 事件的回调被执行。这将进入JavaScript上下文。回调可以修改DOM结构。
  3. 一旦回调执行,浏览器就会离开JavaScript上下文并根据DOM更改重新呈现视图。

Data Binding

Digest Cycle Explanation

为了实现双向绑定,指令寄存器观察者。为了让页面更快更高效,我们需要尝试减少我们创建的所有观察者。所以在使用双向装订时应该小心 - 即只有在真正需要时才使用它。否则,使用单程:

<h1> {{ ::vm.title }} </h1>

这是很明显的是,网页的标题可能不会在用户的页面上的改变 - 或者需要看到新的,如果它是改变。因此,我们可以使用::在模板链接阶段注册单向绑定。

我看到的观察者爆炸的主要问题是具有数百行的网格。如果这些行有很多列,并且在每个单元格中都有双向数据绑定,那么您需要一个处理。您可以坐下来等待现代时间,以便加载页面!

7

双向绑定几乎完全限于使用ng-model的元素。从视图到模型的方向使用标准事件处理程序来检测必须在模型内更新的更改(例如,onchange)。在$digest期间更新从模型返回到视图的方向。但我们不直接拨打$digest

页面上的每个要响应摘要循环的元素都会在某处使用$watch将侦听器和表达式附加到其范围。当您编写{{ foo() }}或当您使用ng-model='user.name'时,内部会有一个以您的名义致电$watch的Javascript表达式,该表达式将在每次运行摘要循环时运行。这种注册可能发生在模板的编译过程中(我们的第一个例子),或者可能发生在指令的链接阶段(我们的第二个例子)。

这里没有魔法。附加的监听器是常规函数 - 在我们的示例中,为您提供了表达式foo()的监听器,它将更新页面上的html文本,而表达式user.name的监听器将调用setTextsetOption,或者ng-model已附加的特定输入所需的任何内容。

尽管angular可以处理大部分的聆听,但您可以在任何可以访问范围的函数中手动附加您自己的监听器表达式(范围非常重要,因为如果相应部分该页面被删除)。注意多余。绑定不是免费的,绑定的东西越多,页面响应越慢。一次性绑定是降低成本的一种方法。使用$on$emit$broadcast是另一个。

那么什么时候被摘要叫?这当然不是自动的。如果摘要循环正在运行,则表示有人在其作用域或根作用域上的某个地方称为$applyng-model重视处理程序,它将响应常规的html事件,并将以您的名义致电$apply。但另一方面,foo()将永远不会被调用,直到其他位的脚本某处调用$apply。幸运的是,您填写的大部分函数都是通过调用$apply来包装这些函数的,因此您不必经常自己拨打电话(例如,$timeout包装为$apply,这就是我们用它代替setTimeout的原因) 。但是,如果您使用的是角度范围以外的事物(连接到事件的第三方库),则需要记得自己拨打$apply,并且就像上面一样,您可以通过在有权访问的任何地方拨打$apply来手动执行此操作到一个范围。

1

为了使数据绑定成为可能,AngularJS使用$ watch API来观察范围的变化。 AngularJS为范围上的每个变量注册观察者以观察其中的值。如果范围上的变量值得到更改,则视图会自动更新。

这是因为$摘要循环被触发。因此,AngularJS处理当前范围和子节点上的所有注册观察者,并检查更新并调用专用观察者侦听器,直到模型稳定并且没有更多的侦听器被触发。一旦$ digest循环完成执行,浏览器就会重新渲染DOM并反映更改

默认情况下,作用域上的每个变量都由angular观察。通过这种方式,不必要的变量也会被耗费时间的角度观察到,因此页面变得越来越慢。