如何使ng-repeat内的点击事件只重新渲染受影响的项目(即不运行$apply)?

12 浏览
0 Comments

如何使ng-repeat内的点击事件只重新渲染受影响的项目(即不运行$apply)?

我的示例代码(下面)提出了两个问题:\n

    \n

  1. 在加载页面时,每个项目调用\"renderthis\"函数两次
  2. \n

  3. 主要问题是 - 点击按钮后,我假设在eval\'ing执行doit()表达式之后,ng-click会在作用域上调用$apply,这会导致每个项目的两个DOM元素重新渲染..现在,我理解这里每个项目的作用域与父作用域有些奇怪的隔离或传递关系,这些是我尚未掌握的东西..是否有办法使ng-click只在每个项目的子作用域上调用$digest或类似的操作?\n
  4. \n

\n以下是我的代码:\nhtml:\n


     
  • {{item.title}} {{renderthis()}} {{item.number}}

\nJS:\n

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}];
});

\n或者查看这个plnkr:\nhttp://plnkr.co/edit/VkR82lbJ0Mi2z12RqBfW

0
0 Comments

问题出现的原因是ng-click事件会触发$scope.$apply(),导致ng-repeat中的所有项都会被重新渲染,而不仅仅是受到点击事件影响的项。

解决方法是使用ngp-local-click替代ng-click。ngp-local-click是一个AngularJS扩展,可以让点击事件只重新渲染受到影响的项,而不会运行$scope.$apply()。

以下是使用ngp-local-click的示例代码:

{{item.name}}

在上面的代码中,ngp-local-click指令被用于ng-repeat的每一项中。当点击某一项时,handleClick函数会被调用,并且只有该项会被重新渲染,其他项不会受到影响。

要使用ngp-local-click,需要先在项目中引入ng-perf库。具体可以参考ng-perf的GitHub仓库:https://github.com/ansukla/ng-perf

通过使用ngp-local-click,我们可以避免不必要的渲染,提高AngularJS应用的性能。

0
0 Comments

AngularJS中的ng-click指令会触发$digest循环,而$digest循环会检查所有的$watch。在视图中的每一组{{}}都会设置一个$watch。当点击按钮时,会调用renderthis()方法并打印log信息,这是因为ng-click触发了$digest循环。

关于“页面加载时每个项被调用两次”的问题,这是因为Angular在第一个$digest循环中检测到有变化时,会运行另一个$digest循环以确保所有的模型都稳定下来。

在给定的示例中,点击按钮不会对作用域进行任何更改,但是仍然会为所有项的作用域调用renderthis()方法。这意味着重新渲染刚刚发生了吗?如果renderthis()是一个应该在每个项中运行并执行一些繁重操作的函数,并且列表中有10000个项,那么点击一个按钮将会触发10000个函数调用。如果我自己绑定点击事件并调用scope.$digest,这种情况就不会发生,但是我正在寻找一个更Angular的解决方案。

在上述对话中,讨论了ng-click的工作原理以及如何实现只重新渲染受影响的项的解决方案。要实现这个功能,需要创建一个自定义指令。

0
0 Comments

在ng-repeat中,点击事件会导致整个ng-repeat列表重新渲染,这是因为ng-click指令会调用$apply方法触发脏检查,从而更新整个ng-repeat列表。如果希望点击事件只重新渲染所点击的项而不更新整个列表,可以使用自定义的ng-click指令来替代原生的ng-click指令。

下面是一个修改过的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();
        });
      };
    }];
  }
);

这段代码创建了一个名为xng-click的指令,它使用$parse服务解析点击事件的表达式,并在点击事件发生时手动调用$scope.$digest()方法来触发脏检查。

使用这个修改过的ng-click指令,可以实现点击事件只重新渲染所点击的项。你可以在下面的plnkr链接中查看示例:

[http://plnkr.co/edit/3i7TCEkBtxCFw2ESeyaU](http://plnkr.co/edit/3i7TCEkBtxCFw2ESeyaU)

需要注意的是,这段代码还没有经过完全测试,请谨慎使用。如果你对这段代码有任何改进,请让我知道。

0