为什么ng-style函数应用了两次?

时间:2014-09-19 03:57:42

标签: javascript angularjs

我有一个有角度的应用程序,如:

angular.module('ngStyleApp', [])

.controller('testCtrl', function($scope) {
   $scope.list = [1,2,3];
   $scope.getStyles = function(index) {
       console.log('getting styles for index ' + index);
       return {
           color: 'red'
       };
   };
});

带有相应的标记:

<div ng-app="ngStyleApp">
    <ul ng-controller="testCtrl">
        <li ng-repeat="value in list" ng-style="getStyles($index)">
            {{value}}
        </li>
    </ul>
</div>

可见输出是三个红色列表项,如预期的那样。但该语句总共被记录到控制台6次,这意味着视图呈现两次:

getting styles for index 0
getting styles for index 1
getting styles for index 2
getting styles for index 0
getting styles for index 1
getting styles for index 2

为什么吗

2 个答案:

答案 0 :(得分:6)

Angular $digest周期至少两次评估ngStyle属性 - 一次获取值,一次检查是否已更改。它实际上一直在迭代,直到值结算,因此可能会多次检查该值。

这是一张图片来说明这一点:

enter image description here

这是一篇很好的博客文章,说明了这一点: angular digest blog

实际上,请试试StackOverflow中的这句话,说得很清楚:

  

当评估观察到的函数时(在$ digest期间),如果它们中的任何一个已经从之前的$摘要发生了变化,那么Angular知道这种变化可能会波及其他观察函数(可能更改的变量用于另一个观察函数)。因此,每个手表都会被重新评估(也称为脏处理),直到所有手表都没有变化。因此,通常情况下,每次摘要会看到2次调用观看函数的次数,有时甚至更多(通过它的10次循环最多10次放弃并报告错误,表示无法稳定)。

(参考here

答案 1 :(得分:1)

这是ngStyle指令的代码:

var ngStyleDirective = ngDirective(function(scope, element, attr) {
  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
    if (oldStyles && (newStyles !== oldStyles)) {
      forEach(oldStyles, function(val, style) { element.css(style, '');});
    }
    if (newStyles) element.css(newStyles);
  }, true);
});

请注意,scope.$watch有一个attr.ngStyle,该手表会触发两次。

例如,如果您尝试使用ngInit执行相同的操作,您会注意到该函数只被调用一次。现在,让我们看一下ngInit指令的代码,它看起来像这样:

var ngInitDirective = ngDirective({
  priority: 450,
  compile: function() {
    return {
      pre: function(scope, element, attrs) {
        scope.$eval(attrs.ngInit);
      }
    };
  }
});

请注意,此指令中没有watch