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

How do I use $scope.$watch and $scope.$apply in AngularJS?

我不知道如何使用$scope.$watch$scope.$apply。官方文件没有帮助。

我不明白的是:

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

我试过这个教程,但对$watch$apply的理解是理所当然的。

$apply$watch是做什么的,我如何适当地使用它们?


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

摘要循环和$scope

首先,AngularJS定义了所谓的消化循环的概念。这个循环可以看作是一个循环,在这个循环中,AngularJS检查所有$scope所监视的所有变量是否有任何变化。因此,如果您在控制器中定义了$scope.myVar并且这个变量被标记为被监视,那么您就隐式地告诉AngularJS监视每个iter中myVar的变化。回路的位置。

一个自然的后续问题是:所有与$scope相关的东西都被监视了吗?幸运的是,没有。如果您要监视$scope中每个对象的更改,那么很快一个摘要循环就需要花费很多时间来评估,并且很快就会遇到性能问题。这就是为什么AngularJS团队给了我们两种方法来声明一些$scope变量被监视(如下所示)。

$watch有助于监听$scope更改

有两种方法可以声明一个$scope变量被监视。

  • 通过表达式{{myVar}}在模板中使用它
  • 通过$watch服务手动添加
  • 广告1)这是最常见的场景,我确信您以前见过,但您不知道这在后台创建了一个手表。是的,它有!使用AngularJS指令(如ng-repeat)也可以创建隐式手表。

    广告2)这就是你自己制作手表的方法。当附加到$scope的值发生变化时,$watch服务帮助您运行一些代码。它很少使用,但有时是有用的。例如,如果希望在每次"myvar"更改时运行一些代码,可以执行以下操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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
        };
    }

    $apply允许将更改与摘要循环集成

    您可以将$apply函数视为集成机制。你看,每次你直接改变一些附加到$scope对象上的被监视变量,AngularJS就会知道改变已经发生了。这是因为AngularJS已经知道监视这些变化。因此,如果它发生在由框架管理的代码中,那么摘要循环将继续进行。

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

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

    所有这些如何与DOM相关?

    好吧,既然你已经知道了这一切,你真的应该再次学习这个教程。摘要循环将通过评估连接到所有$scope的每个观察程序,确保UI和javascript代码保持同步,只要没有任何变化。如果在摘要循环中不再发生更改,则认为已完成。

    可以在控制器中显式地将对象附加到$scope对象,也可以在视图中直接以{{expression}}形式声明这些对象。

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

    进一步阅读:

    • 做你自己的角度,第1部分:范围和摘要


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

    $apply和$watch都是作用域方法,与DOM无关。

    概念页面(部分"运行时")对$digest循环、$apply、$evalasync队列和$watch列表有很好的解释。以下是正文附带的图片:

    $digest loop

    任何代码都可以访问作用域–通常,控制器和指令(它们的链接函数和/或控制器)可以设置一个"watchExpression",AngularJS将根据该作用域进行评估。每当AngularJS进入它的$Digest循环(特别是"$Watch List"循环)时,就会发生这种评估。可以观察单个范围属性,可以定义一个函数来同时观察两个属性,可以观察数组的长度等。

    当发生"inside angularjs"的情况时,例如,您输入一个启用了angularjs双向数据绑定(即使用ng模型)的文本框,$http回调激发等。–$apply已经被调用,因此我们位于上图中的"angularjs"矩形内。将计算所有观察表达式(可能不止一次–,直到检测不到进一步的更改为止)。

    当发生"outside angularJS"–的情况时,例如,在指令中使用bind(),然后该事件激发,导致调用回调,或者某些jquery注册的回调激发–我们仍然处于"本机"矩形中。如果回调代码修改了任何$watch正在监视的内容,则调用$apply进入AngularJS矩形,使$digest循环运行,因此AngularJS将注意到更改并发挥其魔力。


    这个博客已经涵盖了所有创造例子和可以理解的解释。好的。

    AngularJS $scope函数$watch(), $digest()$apply()是AngularJS的一些核心函数。了解$watch()$digest()$apply()对于理解angularjs是必不可少的。好的。

    当您从视图中的某个地方创建到$scope对象上变量的数据绑定时,AngularJS会在内部创建一个"监视"。手表意味着AngularJS会观察$scope object上变量的变化。框架是"监视"变量。手表是使用$scope.$watch()函数创建的,我将在本文稍后介绍该函数。好的。

    在应用程序的关键点,AngularJS调用$scope.$digest()函数。此函数迭代所有监视,并检查任何被监视的变量是否已更改。如果被监视的变量已更改,则调用相应的侦听器函数。listener函数做它需要做的任何工作,例如更改HTML文本以反映被监视变量的新值。因此,$digest()函数触发数据绑定更新。好的。

    大多数时候,AngularJS会为您调用$scope.$watch()和$scope.$digest()函数,但在某些情况下,您可能需要自己调用它们。因此,了解它们是如何工作的真的很好。好的。

    $scope.$apply()函数用来执行一些代码,然后调用$scope.$digest(),这样就检查了所有的监视,调用了相应的监视侦听函数。当将angularJS与其他代码集成时,$apply()函数非常有用。好的。

    我将在本文的其余部分中详细介绍$watch(), $digest()$apply()函数。好的。$监视()

    $scope.watch()函数创建某个变量的监视。注册手表时,您将两个函数作为参数传递给$watch()函数:好的。

    • 一个值函数
    • 侦听器函数

    下面是一个例子:好的。

    1
    2
    3
    $scope.$watch(function() {},
                  function() {}
                 );

    第一个函数是值函数,第二个函数是侦听函数。好的。

    value函数应返回正在监视的值。然后,AngularJS可以根据Watch函数上次返回的值检查返回的值。这样,AngularJS可以确定值是否已更改。下面是一个例子:好的。

    1
    2
    3
    $scope.$watch(function(scope) { return scope.data.myVar },
                  function() {}
                 );

    此示例valule函数返回$scope变量scope.data.myVar。如果这个变量的值改变,将返回一个不同的值,angularJS将调用listener函数。好的。

    请注意,value函数如何将作用域作为参数(名称中没有$)。通过这个参数,value函数可以访问$scope及其变量。如果需要的话,value函数也可以监视全局变量,但大多数情况下,您会看到一个$scope变量。好的。

    如果值发生变化,listener函数应该做它需要做的任何事情。也许您需要更改另一个变量的内容,或者设置HTML元素或其他内容。下面是一个例子:好的。

    1
    2
    3
    4
    5
    6
    $scope.$watch(function(scope) { return scope.data.myVar },
                  function(newValue, oldValue) {
                      document.getElementById("").innerHTML =
                         "" + newValue +"";
                  }
                 );

    此示例将HTML元素的内部HTML设置为变量的新值,嵌入到B元素中,使值变为粗体。当然,您可以使用代码{{ data.myVar }来完成这项工作,但这只是您在listener函数中可以做的一个示例。好的。$DESTEVER()

    $scope.$digest()函数遍历$scope object中的所有表及其子$scope对象(如果有)。当$digest()迭代手表时,它调用每个手表的value函数。如果value函数返回的值与上次调用它时返回的值不同,则调用该监视的侦听器函数。好的。

    只要AngularJS认为有必要,就调用$digest()函数。例如,在执行按钮单击处理程序之后,或者在执行AJAX调用返回之后(在执行done()/fail()回调函数之后)。好的。

    您可能会遇到一些角情况,其中AngularJS不为您调用$digest()函数。您通常会注意到数据绑定不会更新显示的值,从而检测到这一点。在这种情况下,打电话给$scope.$digest(),它应该可以工作。或者,您可以使用$scope.$apply(),我将在下一节中解释。好的。$Apple()

    $scope.$apply()函数将函数作为参数执行,然后在内部调用$scope.$digest()。这使您更容易确保检查所有监视,从而刷新所有数据绑定。下面是一个$apply()示例:好的。

    1
    2
    3
    $scope.$apply(function() {
        $scope.data.myVar ="Another value";
    });

    作为参数传递给$apply()函数的函数将更改$scope.data.myVar的值。当函数退出时,AngularJS将调用$scope.$digest()函数,以便检查所有监视值的变化。好的。例子

    为了说明$watch()$digest($apply()是如何工作的,请看下面的示例:好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
        {{data.time}}

        <br/>
        <button ng-click="updateTime()">update time - ng-click</button>
        <button id="updateTimeButton"  >update time</button>




        var module       = angular.module("myapp", []);
        var myController1 = module.controller("myController", function($scope) {

            $scope.data = { time : new Date() };

            $scope.updateTime = function() {
                $scope.data.time = new Date();
            }

            document.getElementById("updateTimeButton")
                    .addEventListener('click', function() {
                console.log("update time clicked");
                $scope.data.time = new Date();
            });
        });

    他的示例将$scope.data.time变量绑定到一个插值指令,该指令将变量值合并到HTML页面中。这个绑定在$scope.data.time variable上创建了一个内部监视。好的。

    该示例还包含两个按钮。第一个按钮有一个ng-click监听器连接到它。单击该按钮时,将调用$scope.updateTime()函数,然后AngularJS调用$scope.$digest()以更新数据绑定。好的。

    第二个按钮从控制器函数内部获取附加到它的标准JavaScript事件侦听器。单击第二个按钮时,将执行侦听器函数。如您所见,两个按钮的侦听器函数的作用几乎相同,但当调用第二个按钮的侦听器函数时,数据绑定不会更新。这是因为执行第二个按钮的事件侦听器后,不会调用$scope.$digest()。因此,如果单击第二个按钮,时间将在$scope.data.time变量中更新,但不会显示新的时间。好的。

    要解决这个问题,我们可以向按钮事件侦听器的最后一行添加一个$scope.$digest()调用,如下所示:好的。

    1
    2
    3
    4
    5
    6
    document.getElementById("updateTimeButton")
            .addEventListener('click', function() {
        console.log("update time clicked");
        $scope.data.time = new Date();
        $scope.$digest();
    });

    除了在button listener函数中调用$digest()之外,您还可以使用这样的$apply()函数:好的。

    1
    2
    3
    4
    5
    6
    7
    document.getElementById("updateTimeButton")
            .addEventListener('click', function() {
        $scope.$apply(function() {
            console.log("update time clicked");
            $scope.data.time = new Date();
        });
    });

    注意如何从按钮事件侦听器内部调用$scope.$apply()函数,以及如何在作为参数传递给$apply()函数的函数内部执行$scope.data.time变量的更新。当$apply()函数调用完成时,angularjs在内部调用$digest(),因此所有数据绑定都会更新。好的。好啊。


    AngularJS扩展了这个事件循环,创建了一个名为AngularJS context的东西。

    $监视()

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

    1
    2
    User: <input type="text" ng-model="user" />
    Password: <input type="password" ng-model="pass" />

    这里我们有绑定到第一个输入的$scope.user,还有绑定到第二个输入的$scope.pass。为此,我们将两个$watches添加到$watch列表中。

    当加载模板时,也就是在链接阶段,编译器将查找每个指令并创建所需的所有$watches。

    AngularJS提供$watch$watchCollection$watch(true)。下面是一个简洁的图表,解释了从观察者那里深入了解到的所有三个问题。

    Enter image description here

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    angular.module('my_app',[]).controller('myctrl',myctrl)函数myctrl($scope,$timeout){$scope.users=["name":"vinoth<hr><P>我发现了非常深入的视频,包括<wyn>$watch</wyn>、<wyn>$apply</wyn>、<wyn>$digest</wyn>和消化周期:</P><ul><li><P>AngularJS-了解观察者,$watch,$watchgroup,$watchcollection,ng change</P></li><li><P>AngularJS-理解摘要循环(摘要阶段或摘要过程或摘要循环)</P></li><li><P>AngularJS教程-了解$apply和$digest(深入)</P></li></ul><P>以下是这些视频中用来解释概念的几张幻灯片(以防万一,如果上面的链接被删除/不起作用)。</P><P><img src="//i1.wp.com/i.stack.imgur.com/XAR8i.png" alt="Enter image description here"></P><P>在上面的图像中,"$scope.c"不会被监视,因为它不会用于任何数据绑定(在标记中)。另外两个(<wyn>$scope.a</wyn>和<wyn>$scope.b</wyn>将被监视。</P><P><img src="//i1.wp.com/i.stack.imgur.com/ioG04.png" alt="Enter image description here"></P><P>从上图中:基于各自的浏览器事件,AngularJS捕获该事件,执行摘要循环(通过所有观察进行更改),执行观察函数并更新DOM。如果不是浏览器事件,可以使用<wyn>$apply</wyn>或<wyn>$digest</wyn>手动触发摘要循环。</P><P>关于<wyn>$apply</wyn>和<wyn>$digest</wyn>的更多信息:</P><P><img src="//i1.wp.com/i.stack.imgur.com/LuBhi.png" alt="Enter image description here"></P><hr><P>还有<wyn>$watchGroup</wyn>和<wyn>$watchCollection</wyn>。具体来说,如果您想调用函数来更新一个视图中有多个属性而不是DOM对象的对象(例如画布中的其他视图、WebGL或服务器请求),则<wyn>$watchGroup</wyn>非常有用。这里是文档链接。</P><div class="suo-content">[collapse title=""]<ul><li>我本可以评论一下江户一号〔4〕,但我看你已经评论过了。这里是关于安古拉吉斯网站的文档。他们提供了一个非常好的视觉效果的<wyn>$watch</wyn>深度。注意,信息靠近页面底部。</li></ul>[/collapse]</div><p><center>[wp_ad_camp_2]</center></p><hr><P>读完以上所有的,无聊和困倦(对不起,但是真的)。技术性强,深入细致,干燥。我为什么要写作?因为AngularJS是巨大的,许多相互关联的概念可以让任何人发疯。我经常问自己,我是否不够聪明,不能理解他们?不!这是因为很少有人能用一种虚拟语言来解释这项技术,而不需要所有的术语!好吧,让我试试:</P><P>1)它们都是事件驱动的。(我听到笑声,但继续读下去)</P><blockquote>
      <p>
    If you don't know what event-driven is Then
      think you place a button
      on the page, hook it up w/ a function using"on-click",  waiting for
      users to click on it to trigger the actions you plant inside the
      function.    Or think of"trigger" of SQL Server / Oracle.
    </p>
    </blockquote><P>2)$watch是"点击"。</P><blockquote>
      <p>
    What's special about is it takes 2 functions as parameters, first one
      gives the value from the event, second one takes the value into
      consideration...
    </p>
    </blockquote><P>3)$Digest是一个不知疲倦地四处检查的老板,布拉布拉布拉,但是一个好老板。</P><P>4)$apply为您提供了手动操作的方式,例如防故障(如果单击不起作用,则强制它运行)。</P><P>现在,让我们让它可视化。想象一下,这样更容易抓住想法:</P><P>在餐馆里,</P><P>-服务员应该接受顾客的订单,这是</P>[cc]$watch(
      function(){return orders;},
      function(){Kitchen make it;}
    );

    -经理跑来跑去确保所有服务员都醒着,对顾客的任何变化做出反应。我是$digest()

    -业主有权按要求驾驶所有人,这是$apply()