Javascript 如何在ng repeat only内使单击事件重新呈现受影响的项目(即,不运行$apply)?
我的示例代码(下面)提出了两个问题:Javascript 如何在ng repeat only内使单击事件重新呈现受影响的项目(即,不运行$apply)?,javascript,html,angularjs,Javascript,Html,Angularjs,我的示例代码(下面)提出了两个问题: “renderthis”函数在加载页面时,每项调用两次 主要问题-单击按钮时,我假设在计算doit()表达式之后,ng click调用作用域上的$apply,这会导致每个项的两个DOM元素被重新呈现。。现在,我了解到这里每个项目的范围都以某种方式绑定到父范围,或者通过某种奇怪的隔离、转换或诸如此类的东西与之相关,这些我还没有掌握。。是否有一种方法可以使ng click only调用$digest在每个项或类似项的子范围内 这是我的密码: html: 或参见本
@阿泰姆有一个好主意。总而言之,由于Angular在第一个$digest周期中发现了一些变化,因此它运行另一个周期以确保所有模型都稳定下来(没有变化)。在与@Mark进行了一些乒乓球之后(见下文),有人建议我将问题重新表述为这样的问题:“如何在ng repeat作用域内使单击事件仅重新呈现受影响的项目(即,不运行$apply)”这是为了强调,正如Mark所解释的,使用“ng click”本身是不太可能的,因为它发出硬编码的“$apply”,并运行摘要循环等(请参阅下文) 我将接受我自己的答案,其中包括我自己版本的ng click,它使用$digest而不是$apply,因此不会触发所有ng-repeat'ed项目的重新呈现 以下是修订后的ng click代码(xng click): 下面是一个plnkr演示:
.您可以尝试使用ngp本地单击而不是ng单击->请查看此plnkr:。单击其中一个按钮不会更改范围中的任何内容,但仍会为两个项目的范围调用“renderthis”函数。这是否意味着刚刚发生了重新渲染?如果“renderthis”呢“是一个功能,应该每个项目运行,并进行一些繁重的工作,我的列表中有10000个项目。”。。如果我自己绑定单击并调用scope.$digest,这不会发生,但我正在寻找一个更具角度性的解决方案。(@ayal,我在发布之前已经测试了您的plnkr。)因为在您的视图中有{}个
renderthis()
,Angular会自动为此设置一个$watch。只要调用$apply,就会检查该手表,从而调用renderthis()方法。如果这对您意味着“渲染”,则正在进行渲染。(对我来说,“渲染”意味着浏览器必须重新绘制可见页面的一部分,因为DOM中的某些内容发生了更改——当您单击按钮时,DOM中的任何内容都不会更改。因此,对我来说,没有渲染)。作用域。$digest仍将导致检查视图中的所有$watches。无论此处的“render”是否正确,事实仍然是,如果该列表中有1000000个项目,单击其中一个项目的作用域将触发1000000个函数调用。。另外,请看这个forked plnkr(),在其中我不再使用ng click-我自己绑定click事件并调用$digest,这一次即使对范围进行了实际更改。在这种情况下,列表中的其他元素没有“呈现”(尽管对第一项的“renderthis”的双重调用对我来说仍然非常奇怪),这或多或少(可能更少)是我期望ng click会做的事情:。(代码几乎相同,只是它调用$digest)@ayal,我喜欢你的最后一把小提琴。虽然我认为我回答了提出的问题(即,否,ng click不能在事件发生的子作用域上仅运行$digest),但我建议1)将问题改写为以下内容:如何使ng repeat作用域内的click事件仅重新呈现受影响的项(即,不运行$apply)?2) 把你的最后一把小提琴作为答案,并接受它。我心里至少还有两个问题,所以我想参考这样的答案。这还没有经过彻底的测试,所以使用风险自负。如果你对此有所改进,请告诉我。
<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>
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}];
});
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();
});
};
}];
}
);