6

在 Angular 中什么被认为是“观察者”?观察者本身是观察者的唯一类型,还是其他 Angular 构造(如ngModel观察者)也是如此?

还是我错过了大局?例如,观察者是什么使指令喜欢ngModel工作?

更新:有没有办法判断何时存在观察者?在测试中我想知道什么时候调用 scope.$digest()

4

3 回答 3

2

watchers只不过是脏检查,它跟踪旧值和新值

他们在每个摘要周期都得到评估。它可以是范围变量或任何表达式的组合。Angular 确实在每个摘要循环中收集所有这些观察者并将其维护在$$watchers数组中。console.log($scope.$watchers)您可以通过在控制器内部进行操作来查看有多少观察者。

标记

<body class="container" ng-controller="myCtrl">
  Hello {{test}}
  I'm test to show $$watchers {{test1}}
  <div ng-show="show">SHowiing this div using ng-show</div>
  <div ng-if="show">SHowiing this div using ng-show</div>
  Watcher is not compulsary that should scope variables {{'1'}}
</body>

Plunkr

在上面的代码中猜测有多少观察者,你可以看到有 3 个{{}}插值指令将放置在观察者数组中,然后如果你在控制台中看到$scope.$$watchers它将显示 5 个观察者。

它怎么会显示 5 个观察者。正如我们只能看到 3,实际上我们已经使用了ng-showandng-if指令,它在内部放置$watch在其属性值中提供的表达式上。& 这些表达式会在每个摘要循环中进行评估。

您还可以使用 $watch(deep/simple watch) &创建自定义观察者$watchGroup

你也可以让 watcher use $attrs.$observe,它的工作方式与 watch 相同,但它唯一的特殊之处在于它适用于插值变量。

$attrs.$observe('test',function(value){
    alert('')
});

大多数角度指令在内部使用观察器,如ng-repeat, ng-show, ng-if, ng-include, ng-switch, ng-bind, 插值指令{{}}, 过滤器等。它们在内部放置观察器来管理两种方式绑定的东西。

于 2015-08-03T18:18:38.830 回答
1

观察者(如果我们只采用您所基于的文档)是角度机制,旨在以双向绑定样式在任何角度摘要周期中观察变量或函数结果;不管摘要循环的触发事件是什么。

我将任何能够根据可能发生的任何事件触发某些代码的 Angular 机制称为“观察者”。

通常,要创建 Watcher,您应该使用:$scope.watch(...)

请注意,最好尽可能避免观察者。
实际上,它们的回调将在每个摘要周期触发以执行脏检查;经常影响性能。

ng-model与观察者的概念无关。
ng-model只是一种将某些变量从视图绑定到控制器的方法。
它们是两个截然不同的概念。

于 2015-08-03T18:03:05.190 回答
1

为了说明 $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() 函数是如何从按钮事件侦听器内部调用的,以及 $scope.data.time 变量的更新是如何在作为参数传递给 $apply() 函数的函数内部执行的。当 $apply() 函数调用完成 AngularJS 在内部调用 $digest() 时,所有数据绑定都会更新。

于 2017-02-01T11:11:16.030 回答