数据绑定在AngularJS中如何工作?

JavaScript

神奇西里泡芙

2020-03-09

数据绑定在AngularJS框架中如何工作

我尚未在其网站上找到技术细节数据从视图传播到模型时,或多或少地清楚了它是如何工作的。但是,AngularJS如何在没有设置者和获取者的情况下跟踪模型属性的变化?

我发现有些JavaScript观察程序可以完成这项工作。但是Internet Explorer 6Internet Explorer 7不支持它们那么AngularJS如何知道我更改了以下内容并在视图中反映了此更改?

myobject.myproperty="new value";

第214篇《数据绑定在AngularJS中如何工作?》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

11个回答
古一JinJin 2020.03.09

Angular.js为我们在视图中创建的每个模型创建一个观察者。每当更改模型时,都会向该模型添加“ ng-dirty”类,因此观察者将观察所有具有“ ng-dirty”类的模型,并在控制器中更新其值,反之亦然。

Itachi米亚斯丁 2020.03.09

AngularJs支持双向数据绑定
表示您可以访问数据View-> ControllerController-> View

对于前

1)

// If $scope have some value in Controller. 
$scope.name = "Peter";

// HTML
<div> {{ name }} </div>

O / P

Peter

您可以ng-model像这样绑定数据
-2)

<input ng-model="name" />

<div> {{ name }} </div>

在上面的示例中,无论输入用户提供什么,它都将在<div>标签中可见

如果要将html的输入绑定到控制器:
-3)

<form name="myForm" ng-submit="registration()">
   <label> Name </lbel>
   <input ng-model="name" />
</form>

如果您想name在控制器中使用输入

$scope.name = {};

$scope.registration = function() {
   console.log("You will get the name here ", $scope.name);
};

ng-model绑定我们的视图并将其呈现为expression {{ }}
ng-model是在视图中向用户显示并与用户进行交互的数据。
因此在AngularJs中绑定数据很容易。

蛋蛋伽罗猿 2020.03.09

这是一个使用输入字段与AngularJS进行数据绑定的示例。我稍后再解释

HTML代码

<div ng-app="myApp" ng-controller="myCtrl" class="formInput">
     <input type="text" ng-model="watchInput" Placeholder="type something"/>
     <p>{{watchInput}}</p> 
</div>

AngularJS代码

myApp = angular.module ("myApp", []);
myApp.controller("myCtrl", ["$scope", function($scope){
  //Your Controller code goes here
}]);

如您在上面的示例中看到的那样,AngularJS用于ng-model侦听和观察HTML元素(尤其是input字段)上发生的情况当某事发生时,做某事。在我们的案例中,ng-model使用髭标记绑定到我们的视图{{}}输入字段中键入的任何内容都会立即显示在屏幕上。这就是使用最简单形式的AngularJS进行数据绑定的好处。

希望这可以帮助。

Codepen上查看工作示例

null 2020.03.09
  1. 单向数据绑定是一种从数据模型中获取值并将其插入HTML元素的方法。无法从视图更新模型。它在经典模板系统中使用。这些系统仅在一个方向上绑定数据。

  2. Angular应用程序中的数据绑定是模型和视图组件之间的数据自动同步。

数据绑定使您可以将模型视为应用程序中的单一事实来源。该视图始终是模型的投影。如果模型发生更改,则视图将反映更改,反之亦然。

神无Green前端 2020.03.09

AngularJS借助三个强大的函数处理数据绑定机制: $ watch()$ digest()$ apply()大多数时候,AngularJS都会调用$ scope。$ watch()和$ scope。$ digest(),但是在某些情况下,您可能必须手动调用这些函数才能使用新值进行更新。

$ watch():-

该函数用于观察$ scope变量的变化。它接受三个参数:表达式,侦听器和相等对象,其中侦听器和相等对象是可选参数。

$ digest() -

此函数遍历$ scope对象及其子$ scope对象
(如果有)中的所有监视。当$ digest()遍历表时,它将检查表达式的值是否已更改。如果值已更改,AngularJS将使用新值和旧值调用侦听器。每当AngularJS认为必要时,都会调用$ digest()函数。例如,在单击按钮后或在进行AJAX调用后。在某些情况下,AngularJS可能不会为您调用$ digest()函数。在这种情况下,您必须自己调用它。

$ apply() -

Angular只会自动魔术地更新AngularJS上下文中的那些模型更改。当您确实在Angular上下文之外的任何模型中进行更改(例如浏览器DOM事件,setTimeout,XHR或第三方库)时,则需要通过手动调用$ apply()来通知Angular更改。当$ apply()函数调用完成时,AngularJS在内部调用$ digest(),因此所有数据绑定都将更新。

路易米亚 2020.03.09

碰巧我需要将一个人的数据模型与表单联系起来,我所做的是将数据直接与表单进行映射。

例如,如果模型具有以下内容:

$scope.model.people.name

形式的控制输入:

<input type="text" name="namePeople" model="model.people.name">

这样,如果您修改对象控制器的值,这将自动反映在视图中。

我通过的模型从服务器数据中更新的示例是,当您要求邮政编码和基于书面负载的邮政编码时,列出了与该视图相关联的殖民地和城市列表,并且默认情况下为用户设置了第一个值。我做得很好,发生的事情是,angularJS有时需要几秒钟来刷新模型,为此,您可以在显示数据时放置微调器。

宝儿小哥小卤蛋 2020.03.09

显然,没有定期检查Scope附加到它的对象是否有任何更改。并非监视所有附加到作用域的对象。范围原型保持一个$ watchersScope$$watchers$digest被调用对此进行迭代

Angular为$$ watcher的每一个添加了一个watcher

  1. {{expression}}-在您的模板(以及存在表达式的其他任何地方)中或当我们定义ng-model时。
  2. $scope.$watch(‘expression/function’) — In your JavaScript we can just attach a scope object for angular to watch.

$watch function takes in three parameters:

  1. First one is a watcher function which just returns the object or we can just add an expression.

  2. Second one is a listener function which will be called when there is a change in the object. All the things like DOM changes will be implemented in this function.

  3. The third being an optional parameter which takes in a boolean . If its true , angular deep watches the object & if its false Angular just does a reference watching on the object. Rough Implementation of $watch looks like this

Scope.prototype.$watch = function(watchFn, listenerFn) {
   var watcher = {
       watchFn: watchFn,
       listenerFn: listenerFn || function() { },
       last: initWatchVal  // initWatchVal is typically undefined
   };
   this.$$watchers.push(watcher); // pushing the Watcher Object to Watchers  
};

There is an interesting thing in Angular called Digest Cycle. The $digest cycle starts as a result of a call to $scope.$digest(). Assume that you change a $scope model in a handler function through the ng-click directive. In that case AngularJS automatically triggers a $digest cycle by calling $digest().In addition to ng-click, there are several other built-in directives/services that let you change models (e.g. ng-model, $timeout, etc) and automatically trigger a $digest cycle. The rough implementation of $digest looks like this.

Scope.prototype.$digest = function() {
      var dirty;
      do {
          dirty = this.$$digestOnce();
      } while (dirty);
}
Scope.prototype.$$digestOnce = function() {
   var self = this;
   var newValue, oldValue, dirty;
   _.forEach(this.$$watchers, function(watcher) {
          newValue = watcher.watchFn(self);
          oldValue = watcher.last;   // It just remembers the last value for dirty checking
          if (newValue !== oldValue) { //Dirty checking of References 
   // For Deep checking the object , code of Value     
   // based checking of Object should be implemented here
             watcher.last = newValue;
             watcher.listenerFn(newValue,
                  (oldValue === initWatchVal ? newValue : oldValue),
                   self);
          dirty = true;
          }
     });
   return dirty;
 };

如果我们使用JavaScript的setTimeout()函数更新范围模型,则Angular无法知道您可能会更改的内容。在这种情况下,我们有责任手动调用$ apply(),这将触发一个$ digest循环。同样,如果您有一个设置DOM事件侦听器并更改处理程序函数内某些模型的指令,则需要调用$ apply()以确保更改生效。$ apply的主要思想是我们可以执行一些不了解Angular的代码,这些代码可能仍会改变作用域。如果将代码包装在$ apply中,它将调用$ digest()。$ apply()的粗略实现。

Scope.prototype.$apply = function(expr) {
       try {
         return this.$eval(expr); //Evaluating code in the context of Scope
       } finally {
         this.$digest();
       }
};
小卤蛋卡卡西 2020.03.09

图片解释:

数据绑定需要映射

范围中的引用与模板中的引用不完全相同。在对两个对象进行数据绑定时,您需要第三个对象来监听第一个对象并修改另一个对象。

在此处输入图片说明

在这里,当您修改时<input>,您可以触摸data-ref3经典的数据绑定机制将改变data-ref4那么其他{{data}}表达式将如何移动?

事件导致$ digest()

在此处输入图片说明

角保持oldValuenewValue每一个结合。并且在每个Angular事件之后,著名的$digest()循环将检查WatchList以查看是否发生了更改。这些角的事件ng-clickng-change$http完成的... $digest()只要任何将循环oldValue从不同newValue

在上一张图片中,将注意到data-ref1和data-ref2已更改。

结论

有点像鸡蛋和鸡肉。您永远不会知道谁开始,但是希望它在大多数情况下都能按预期运行。

另一点是,您可以轻松理解简单绑定对内存和CPU的深层影响。希望台式机足够胖以应付这一问题。手机不是那么强大。

飞云Tom小宇宙 2020.03.09

我自己想了一段时间。没有二传手,如何AngularJS注意到$scope物体的变化它会轮询他们吗?

它的实际作用是:修改过模型的任何“正常”位置都已经从的胆量中AngularJS调用$apply,因此它在代码运行后会自动为您调用假设您的控制器具有某种连接到ng-click某个元素的方法。由于AngularJS为您将该方法的调用连接在一起,因此有机会$apply在适当的位置进行操作。同样,出现在正确的意见表达,这些被执行AngularJS它确实是这样的$apply

当文档讨论必须$apply手动调用之外的AngularJS代码,它是在讨论运行时并非源于AngularJS调用栈本身的代码

Stafan理查德 2020.03.09

这是我的基本理解。可能是错误的!

  1. 通过将函数(返回要监视的事物)传递给$watch方法来监视项目
  2. 对观看项目的更改必须在该$apply方法包装的代码块内进行
  3. 在方法的末尾,将调用该方法$apply$digest方法将遍历每个手表,并检查自上次$digest运行以来它们是否已更改
  4. 如果发现任何更改,则再次调用摘要,直到所有更改稳定下来。

在常规开发中,HTML中的数据绑定语法会告诉AngularJS编译器为您创建监视,并且控制器方法已在内部运行$apply因此,对于应用程序开发人员而言,这一切都是透明的。

飞云 2020.03.09

Misko已经很好地描述了数据绑定的工作方式,但是我想对数据绑定的性能问题发表自己的看法。

正如Misko所说,大约2000个绑定是您开始发现问题的地方,但是无论如何您在页面上都不应拥有超过2000条信息。这可能是正确的,但并非每个数据绑定都对用户可见。一旦开始使用双向绑定构建任何类型的窗口小部件或数据网格,就可以轻松实现 2000个绑定,而不会出现不良的UX。

例如,考虑一个组合框,您可以在其中键入文本以过滤可用选项。这种控件可能有约150个项目,但仍然非常有用。如果它具有某些额外功能(例如,当前选定选项上的特定类),则每个选项将开始获得3-5个绑定。将其中三个小部件放在页面上(例如,一个用于选择国家/地区,另一个用于选择该国家/地区的城市,而第三个用于选择酒店),您已经在1000到2000个绑定之间。

或考虑公司Web应用程序中的数据网格。每页50行并非不合理,每行可以有10到20列。如果使用ng-repeats构建它,并且/或者在某些使用某些绑定的单元中包含信息,则仅使用此网格就可以达到2000个绑定。

我发现在使用AngularJS时这是一个巨大的问题,到目前为止,我唯一能找到的解决方案是在不使用双向绑定的情况下构造小部件,而不是使用ngOnce,注销观察者和类似技巧或构造使用jQuery和DOM操作构建DOM的指令。我觉得这违背了首先使用Angular的目的。

我很想听听有关其他方法的建议,但是也许我应该写我自己的问题。我想对此发表评论,但事实证明它太长了……

TL; DR
数据绑定可能会导致复杂页面上的性能问题。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android