AngularJS $ watch(),$ digest()和$ apply()

时间:2020-01-09 10:34:02  来源:igfitidea点击:

AngularJS的$ scope函数,$ watch(),$ digest()和$ apply()是AngularJS的一些主要功能。为了理解AngularJS,理解$ watch()$ digest()和$ apply()是必不可少的。

当我们从视图中的某处创建数据绑定到$ scope对象上的变量时,AngularJS在内部创建一个"监视"。监视意味着AngularJS监视$ scope对象上变量的变化。该框架正在"监视"变量。手表是使用$ scope。$ watch()函数创建的,我将在本文后面介绍。

在应用程序的关键点,AngularJS调用了$ scope。$ digest()函数。此函数遍历所有监视,并检查任何监视变量是否已更改。如果监视的变量已更改,则将调用相应的侦听器函数。侦听器功能会执行所需的任何工作,例如更改HTML文本以反映监视变量的新值。因此,$ digest()函数是触发数据绑定更新的函数。

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

$ scope。$ apply()函数用于执行一些代码,然后再调用$ scope。$ digest(),以便检查所有手表并调用相应的手表侦听器函数。当将AngularJS与其他代码集成时,$ apply()函数非常有用。

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

$ watch()

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

  • 值函数
  • 监听器listener函数

这是一个例子:

$scope.$watch(function() {},
              function() {}
             );

第一个功能是值功能,第二个功能是侦听器功能。

值函数应返回正在监视的值。然后,AngularJS可以对照watch函数最后一次返回的值来检查返回的值。这样,AngularJS可以确定值是否已更改。这是一个例子:

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

这个示例valule函数返回$ scope变量scope.data.myVar。如果此变量的值更改,将返回不同的值,并且AngularJS将调用侦听器函数。

注意value函数如何将" scope"作为参数(名称中没有" $")。通过此参数,值函数可以访问$ scope及其变量。如果需要,值函数也可以监视全局变量,但是大多数情况下,我们将监视$ scope变量。

如果值已更改,则侦听器函数应执行所需的任何操作。也许我们需要更改另一个变量的内容,或者设置HTML元素或者其他内容的内容。这是一个例子:

$scope.$watch(function(scope) { return scope.data.myVar },
              function(newValue, oldValue) {
                  document.getElementById("").innerHTML =
                      "" + newValue + "";
              }
             );

本示例将HTML元素的内部HTML设置为变量的新值,并嵌入在使该值变为粗体的b元素中。当然,我们可以使用代码" {{data.myVar}"来完成此操作,但这只是我们可以在侦听器函数中执行的操作的一个示例。

$ digest()

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

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

我们可能会遇到一些极端的情况,其中AngularJS不会为我们调用$ digest()函数。通常,我们会通过注意到数据绑定不会更新显示的值来检测到这一点。在这种情况下,调用$ scope。$ digest()它将起作用。或者,我们可以使用$ scope。$ apply()代替,我将在下一部分中进行解释。

$ apply()

$ scope。$ apply()函数将函数作为参数执行,然后在内部调用$ scope。$ digest()。这使我们更容易确保检查所有手表,从而刷新所有数据绑定。这是一个$ apply()示例:

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

作为参数传递给$ apply()函数的函数将改变$ scope.data.myVar的值。当该函数退出时,AngularJS将调用$ scope。$ digest()函数,以便检查所有手表,以观察值的变化。

例子

为了说明$ watch(),$ digest()和$ apply()的工作方式,请看以下示例:

<div ng-controller="myController">
    {{data.time}}

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

<script>
    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();
        });
    });
</script>

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

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

第二个按钮从控制器函数内部获得一个添加的标准JavaScript事件侦听器。单击第二个按钮时,将执行侦听器功能。如我们所见,两个按钮的侦听器功能几乎相同,但是调用第二个按钮的侦听器功能时,数据绑定不会更新。这是因为在执行第二个按钮的事件侦听器后未调用$ scope。$ digest()。因此,如果我们单击第二个按钮,则时间将在$ scope.data.time变量中更新,但永远不会显示新时间。

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

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

除了在按钮监听器函数中调用$ digest()之外,我们还可以这样使用$ apply()函数:

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(),因此所有数据绑定都将更新。