如何使用$ scope.$ watch和$ scope.$在AngularJS中申请?

ily*_*lyo 1076 angularjs angularjs-scope

我不明白如何使用$scope.$watch$scope.$apply.官方文档没有帮助.

具体我不明白:

  • 它们是否与DOM连接?
  • 如何更新模型的DOM更改?
  • 他们之间的联系点是什么?

我尝试了本教程,但需要理解$watch$apply理所当然.

做什么$apply$watch做什么,以及如何恰当地使用它们?

Łuk*_*man 1727

您需要了解AngularJS如何工作才能理解它.

摘要周期和$范围

首先,AngularJS定义了一个所谓的摘要周期的概念.这个循环可以被认为是一个循环,在此过程中AngularJS会检查所有s所监视的所有变量是否有任何变化$scope.因此,如果您已$scope.myVar在控制器中定义并且此变量已标记为正在观察,那么您将隐式告知AngularJS监视myVar循环的每次迭代中的更改.

一个自然的后续问题是:一切都$scope被观看了吗?幸运的是,没有.如果您要观察对您的每个对象的更改$scope,那么很快就需要花费很长时间来评估摘要循环,您很快就会遇到性能问题.这就是为什么AngularJS团队给我们两种方式来声明一些$scope变量被观察(见下文).

$ watch有助于监听$ scope更改

有两种方法可以将$scope变量声明为被监视.

  1. 通过表达式在模板中使用它 <span>{{myVar}}</span>
  2. 通过$watch服务手动添加

广告1)这是最常见的情况,我相信你以前见过它,但你不知道这在后台创造了一个手表.是的,它有!使用AngularJS指令(例如ng-repeat)也可以创建隐式监视.

广告2)这就是您创建自己手表的方式.$watch服务可以帮助您在附加到的某个值$scope发生更改时运行一些代码.它很少使用,但有时很有帮助.例如,如果您希望每次'myVar'更改时运行一些代码,您可以执行以下操作:

function MyController($scope) {

    $scope.myVar = 1;

    $scope.$watch('myVar', function() {
        alert('hey, myVar has changed!');
    });

    $scope.buttonClicked = function() {
        $scope.myVar = 2; // This will trigger $watch expression to kick in
    };
}
Run Code Online (Sandbox Code Playgroud)

$ apply可以将更改与摘要周期集成

您可以将$apply功能视为集成机制.你看,每当你改变一个直接附加到$scope对象的观察变量时,AngularJS就会知道发生了变化.这是因为AngularJS已经知道要监控这些变化.因此,如果它发生在框架管理的代码中,摘要周期将继续.

但是,有时您希望更改AngularJS世界之外的某些值,并看到更改正常传播.考虑一下 - 你有一个$scope.myVar值将在jQuery的$.ajax()处理程序中修改.这将在未来的某个时刻发生.AngularJS不能等待这种情况发生,因为它没有被指示等待jQuery.

为了解决这个问题,$apply已经介绍过了.它可以让您明确地开始消化循环.但是,您应该只使用它来将一些数据迁移到AngularJS(与其他框架集成),但从不将此方法与常规AngularJS代码结合使用,因为AngularJS会抛出错误.

所有这些都与DOM有什么关系?

好吧,你应该再次按照教程,既然你知道这一切.摘要周期将确保UI和JavaScript代码保持同步,通过评估附加到所有$scopes的每个观察者,只要没有任何变化.如果摘要循环中没有更多的更改,则认为它已完成.

您可以$scope在Controller中显式地将对象附加到对象,也可以{{expression}}直接在视图中以表单形式声明它们.

我希望这有助于澄清有关这一切的一些基本知识.

进一步阅读:

  • "角度检查附加到所有$ scopes的所有变量是否有任何变化" - 我不认为这是正确的.我相信只有Angular(脏)检查已设置$ watch的$ scope属性(请注意,在视图中使用{{}}将自动创建$ watch).另请参见[范围页面](http://docs.angularjs.org/guide/scope)上的"范围$观察性能注意事项"部分. (57认同)
  • @MarkRajcok,你是对的.我改变了我的回复并指出了一篇很好地展示了如何实现的文章. (15认同)
  • 情况可能就是这样.我会试着找一些时间来阅读更多关于它并编辑我的答案. (5认同)
  • 用这个怎么样?("控制为"方法) (3认同)
  • 使用“控件为”对以上信息没有影响。使用this.myVar将myVar放在示波器上。 (2认同)
  • @ŁukaszBachman-“然后,您明确告诉Angular监视更改”。我认为其“隐式”不是“明示” (2认同)
  • @mia,谢谢,好点!我修改了我的回复。 (2认同)

Mar*_*cok 160

在AngularJS中,我们更新模型,我们的视图/模板"自动"更新DOM(通过内置或自定义指令).

$ apply和$ watch都是Scope方法,与DOM无关.

概念页(参考"运行")具有$消化循环的一个很好的解释,$应用中,$ evalAsync队列和$观察名单.这是文本附带的图片:

$ digest循环

无论代码何时访问范围 - 通常是控制器和指令(它们的链接函数和/或它们的控制器) - 都可以设置一个" watchExpression ",AngularJS将根据该范围进行评估.只要AngularJS进入其$ digest循环(特别是"$ watch list"循环),就会发生此评估.您可以观看单个范围属性,您可以定义一个函数来一起观看两个属性,您可以观察数组的长度等.

当事情发生在"AngularJS内部" - 例如,你输入一个启用了AngularJS双向数据绑定的文本框(即使用ng-model),$ http回调触发等等 - $ apply已被调用,所以我们在上图中的"AngularJS"矩形内.将评估所有watchExpressions(可能不止一次 - 直到没有检测到进一步的更改).

当事情发生在"AngularJS之外" - 例如,你在一个指令中使用了bind()然后该事件触发,导致你的回调被调用,或者一些jQuery注册的回调触发 - 我们仍然在"Native"矩形中.如果回调代码修改任何$ watch正在观看的内容,请调用$ apply进入AngularJS矩形,导致$ digest循环运行,因此AngularJS会注意到更改并发挥其魔力.

  • 没有发生神奇的数据传输.通常使用Angular应用程序,您应该更改Angular模型,然后驱动视图/ DOM更新.如果您在Angular之外更新DOM,则必须手动更新模型.`scope.$ apply(scope.model)`将简单地将`scope.model`评估为Angular表达式,然后输入$ digest循环.在你引用的文章中,可能是`scope.$ apply()`就足够了,因为模型已经被$ watch'ed了.stop()函数正在更新模型(我相信toUpdate是对scope.model的引用),然后调用$ apply. (6认同)
  • 我理解这个想法,我不明白的是数据是如何实际传输的.我有一个模型,它是一个包含大量数据的对象,我使用它来操纵DOM.然后其中一些变了.如何将更改的数据放在模型中的正确位置?在这个例子中我用他做的操纵,并最终只是使用`范围.$应用(scope.model)`,我不明白什么样的数据被传输以及它是如何转移到模型中的正确的地方? (5认同)

Tha*_*var 50

AngularJS扩展了这个事件循环,创建了一个名为AngularJS context.

$表()

每次在UI中绑定某些内容时,都会$watch$watch列表中插入一个.

User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />
Run Code Online (Sandbox Code Playgroud)

在这里,我们有$scope.user,第一个输入,我们有$scope.pass,它绑定到第二个输入.这样做我们$watch$watch列表中添加两个es.

当我们的模板被加载,AKA处于链接阶段时,编译器将查找每个指令并创建$watch所需的所有es.

AngularJS提供$watch,$watchcollection$watch(true).下面是一个简洁的图表,解释了从观察者那里获得的所有三个深度.

在此输入图像描述

angular.module('MY_APP', []).controller('MyCtrl', MyCtrl)
function MyCtrl($scope,$timeout) {
  $scope.users = [{"name": "vinoth"},{"name":"yusuf"},{"name":"rajini"}];

  $scope.$watch("users", function() {
    console.log("**** reference checkers $watch ****")
  });

  $scope.$watchCollection("users", function() {
    console.log("**** Collection  checkers $watchCollection ****")
  });

  $scope.$watch("users", function() {
    console.log("**** equality checkers with $watch(true) ****")
  }, true);

  $timeout(function(){
     console.log("Triggers All ")
     $scope.users = [];
     $scope.$digest();

     console.log("Triggers $watchCollection and $watch(true)")
     $scope.users.push({ name: 'Thalaivar'});
     $scope.$digest();

     console.log("Triggers $watch(true)")
     $scope.users[0].name = 'Superstar';
     $scope.$digest();
  });
}
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/2Lyn0Lkb/

$digest

当浏览器收到可由AngularJS上下文管理的事件时,$digest将触发循环.该循环由两个较小的循环组成.一个处理$evalAsync队列,另一个处理队列$watch list.在$digest通过的名单将循环$watch,我们有

app.controller('MainCtrl', function() {
  $scope.name = "vinoth";

  $scope.changeFoo = function() {
      $scope.name = "Thalaivar";
  }
});

{{ name }}
<button ng-click="changeFoo()">Change the name</button>
Run Code Online (Sandbox Code Playgroud)

这里我们只有一个,$watch因为ng-click不会创建任何手表.

我们按下按钮.

  1. 浏览器接收将进入AngularJS上下文的事件
  2. $digest循环运行,并会要求每$表更改.
  3. 由于$watch正在观察$ scope.name中的更改报告更改,因此将强制执行另一个$digest循环.
  4. 新循环没有任何报告.
  5. 浏览器获得控制权,它将更新反映$ scope.name新值的DOM
  6. 这里重要的是进入AngularJS上下文的每个事件都将运行一个$digest循环.这意味着每次我们在输入中写一个字母时,循环都将$watch在此页面中运行检查.

$适用()

如果$apply在事件被触发时调用,它将通过angular-context,但是如果你不调用它,它将在它之外运行.就是这么简单.$apply将在$digest()内部调用循环,它将遍历所有监视以确保使用新更新的值更新DOM.

$apply()方法将触发整个$scope链上的观察者,而该$digest()方法仅触发当前$scope及其的观察者children.当所有较高级别的$scope对象都不需要知道本地更改时,您可以使用$digest().


use*_*687 18

我发现了非常深入的视频覆盖$watch,$apply,$digest并在消化周期:

以下是在这些视频中使用的几张幻灯片来解释这些概念(以防万一,如果删除上述链接/不工作).

在此输入图像描述

在上图中,"$ scope.c"未被监视,因为它未在任何数据绑定中使用(在标记中).另外两个($scope.a$scope.b)将被观看.

在此输入图像描述

从上图:根据各自的浏览器事件,AngularJS捕获事件,执行摘要周期(通过所有手表进行更改),执行监视功能并更新DOM.如果不是浏览器事件,则可以使用$apply或手动触发摘要周期$digest.

更多关于$apply$digest:

在此输入图像描述


Utk*_*waj 17

$watchGroup$watchCollection也.具体来说,$watchGroup如果要调用函数来更新在视图中不具有dom对象的多个属性的对象,例如canvas,webGL或服务器请求中的其他视图,则非常有用.这里是文档链接.


Jeb*_*b50 15

刚读完以上所有内容,无聊而困倦(抱歉,但这是真的).非常技术性,深入,细致,干燥.我为什么要写作?因为AngularJS是庞大的,许多相互关联的概念可以让任何人变得疯狂.我经常问自己,我是不是很聪明才能理解它们?没有!这是因为很少有人可以用所有术语来解释用于dummie语言的技术!好的,让我试试:

1)它们都是事件驱动的东西.(我听到了笑声,但请继续阅读)

如果您不知道什么是事件驱动,那么您可以在页面上放置一个按钮,使用"点击"将其连接到某个功能,等待用户点击它以触发您在其中设置的操作功能.或者想一想SQL Server/Oracle的"触发器".

2)$ watch是"点击".

有什么特别的,它需要2个函数作为参数,第一个给出事件的值,第二个考虑值...

3)$ digest是老板谁不知疲倦地检查,bla-bla-bla但是一个好老板.

4)$ apply为您提供了手动操作的方式,例如防故障(如果点击不启动,则强制它运行.)

现在,让我们让它成为视觉.想象一下,这样可以更容易地抓住这个想法:

在一家餐馆,

- WAITERS应该接受客户的订单,这是

$watch(
  function(){return orders;},
  function(){Kitchen make it;}
);
Run Code Online (Sandbox Code Playgroud)

- 经理跑来跑去确保所有服务员都醒着,以应对客户的任何变化.这是$digest()

- OWNER有能力根据要求驱动每个人,这是$apply()

  • 五岁的孩子可以理解这一点。我感谢这种回答。+1 (2认同)