3

我的示例代码(在那里)提出了两个问题:

  1. 简单地加载页面时,每个项目都会调用“renderthis”函数两次

  2. 主要问题 - 单击按钮时,我假设在评估 doit() 表达式后,ng-click 会在范围上调用 $apply,这会导致每个项目的两个 DOM 元素被重新渲染。现在,我了解这里每个项目的范围以某种方式绑定到父范围或通过一些奇怪的隔离或嵌入或诸如此类的东西与之相关,这是我尚未掌握的东西.. 有没有办法让 ng-click 只调用 $digest在每个项目的子范围或类似的东西上?

这是我的代码:

html:

<body ng-controller="MainCtrl">
     <ul>
        <li ng-repeat="item in items">
        <div>
         <span>{{item.title}}</span> 
         <span>{{renderthis()}}</span>
         <span>{{item.number}}</span>
         <button ng-click="doit()">CLIQUE!</button>
        </div>
        </li>
      </ul>
  </body>

JS:

var app = angular.module('angularjs-starter', []);

app.controller('MainCtrl', function($scope) {
  $scope.doit = function(){
    console.log('doing it for item with title --> ', this.item.title);
  }
  $scope.renderthis = function(){
    console.log('rendering this for item with title -->', this.item.title);
    return '|';
  }
  $scope.items = [{title: 'hello', number: 1}, {title: 'shalom', number: 42}];
});

或者看到这个plnkr:

http://plnkr.co/edit/VkR82lbJ0Mi2z12RqBfW

4

3 回答 3

3

在与@Mark就此进行了一些乒乓球比赛之后(见下文),建议我将问题重新表述为此类问题:“我怎样才能在 ng-repeat 范围内进行点击事件,仅重新渲染受影响的项目(即,不运行 $apply) "正如 Mark 解释的那样,这是为了强调,使用 "ng-click" 本身不太可能解决问题,因为它发出一个硬编码的 "$apply",并且运行一个摘要循环等等..(见下文)

我会接受我自己的答案,其中包括我自己的 ng-click 版本,它使用 $digest 而不是 $apply,因此不会触发所有 ng-repeat'ed 项目的重新渲染。

这是修改后的 ng-click 代码(xng-click):

var xngEventDirectives = {};

angular.forEach(
  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup'.split(' '),
  function(name) {
    var directiveName = directiveNormalize('xng-' + name);
    xngEventDirectives[directiveName] = ['$parse', function($parse) {
      return function(scope, element, attr) {

        var fn = $parse(attr[directiveName]);
        element.bind(name.toLowerCase(), function(event) {
        fn(scope, {$event:event});
        scope.$digest();
        });
      };
    }];
  }
);

这是一个 plnkr 来演示它:

http://plnkr.co/edit/3i7TCEkBtxCFw2ESeyaU

于 2013-02-01T20:28:50.693 回答
2

有没有办法让 ng-click 只在每个项目的子范围内调用 $digest 或类似的东西?

不,要实现此功能,您必须创建自己的指令。

ng-click 触发一个$digest 循环(参见“运行时”部分),它将(除其他外)检查所有 $watches。视图中的每组 {{}} 都会设置一个 $watch。这就是为什么当你点击你会看到来自 renderthis 函数的 log()s 的原因。

除非 $watches 检测到更改,否则我认为不会重新渲染任何内容。

关于“页面加载时每个项目调用两次”:

(由于 watchExpression 可以在每个 $digest 循环中执行多次,当检测到更改时,请准备好多次调用您的侦听器。) -- Scope#$watch API doc

@Artem对 Angular 的摘要循环和脏检查有很好的解释。总而言之,因为 Angular 在第一个 $digest 循环中发现了一些变化,它会运行另一个以确保所有模型都稳定(未更改)。

于 2013-01-30T21:33:20.610 回答
0

您可以尝试 ngp-local-click 而不是 ng-click -> https://github.com/ansukla/ng-perf

于 2014-10-28T17:16:16.463 回答