11

AngularJS 允许你实现双向数据绑定。然而,有趣的部分是它如何检测模型变化?模型通常是一个普通的对象,如下面的代码。我们可以更改 name 属性,$scope.user但是 AngularJS 是如何检测模型更改的呢?AngularJS 是否枚举$scope对象的所有属性?

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

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

3 回答 3

12

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

为了执行摘要循环,$apply(fn)必须运行,这就是您从 JavaScript 进入 Angular 世界的方式。如何$apply(fn)被调用(取自 AngularJs与浏览器的集成):

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

数据绑定

摘要循环说明

为了实现双向绑定,指令注册观察者。为了使页面快速高效,我们需要尝试减少我们创建的所有这些观察者。所以你在使用双向绑定时应该小心——即只在你真正需要的时候使用它。否则使用单向:

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

很明显,当用户在页面上时,页面的标题可能不会改变——或者如果它改变了,则需要查看新的标题。所以我们可以::在模板链接阶段使用注册单向绑定。

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

于 2015-05-24T15:16:01.167 回答
7

双向绑定几乎仅限于使用ng-model. 从视图到模型的方向使用标准事件处理程序来检测必须在模型中更新的更改(例如,onchange)。从模型返回视图的方向在$digest. 但是我们不$digest直接调用。

页面上将响应摘要循环的每个元素都将在某处使用$watch. 当您编写{{ foo() }}或使用 时ng-model='user.name',在内部会使用 Javascript 表达式代表您进行调用$watch,该 Javascript 表达式将在每次运行摘要循环时运行。这种注册可能发生在模板的编译期间(我们的第一个示例),或者它可能发生在指令的链接阶段(我们的第二个示例)。

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

虽然 Angular 可以处理大部分监听,但您可以在任何可以访问范围的函数中手动将自己的监视表达式与自己的监听器附加在一起(范围很重要,因为如果页面的相应部分被删除,我们将拆除这些监听器)。注意多余。绑定不是免费的,绑定的东西越多,页面响应的速度就越慢。一次性绑定是降低此成本的一种方法。$on$emit和一起使用$broadcast是另一个。

那么什么时候调用摘要呢?这当然不是自动的。如果摘要循环正在运行,则意味着有人在某个地方调用$apply了他们的范围或根范围。 ng-model附加将响应常规 html 事件并$apply代表您进行调用的处理程序。但是foo(),另一方面,永远不会被调用,直到某处的其他一些脚本调用$apply. 幸运的是,您为 angular wrap 填写的大多数函数都使用对 的调用来包装这些函数$apply,因此您不必经常自己进行调用(例如,$timeout用 包装$apply,这就是我们使用它而不是 的原因setTimeout)。但是,如果您使用的是 angular 范围之外的东西(连接到事件的 3rd 方库),您需要记住调用$apply您自己,就像上面一样,您可以通过调用$apply您可以访问范围的任何地方手动执行此操作。

于 2015-05-24T16:17:37.107 回答
1

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

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

默认情况下,角度观察范围内的每个变量。通过这种方式,不必要的变量也会被角度观察到,这是耗时的,因此页面变得很慢。

于 2016-12-05T06:19:18.590 回答