3

私のサンプル コード (そこにあります) は 2 つの問題を引き起こします。

  1. 「renderthis」関数は、単にページをロードするときにアイテムごとに 2 回呼び出されます

  2. 主な問題 - ボタンをクリックすると、doit() 式を評価した後、ng-click がスコープで $apply を呼び出し、各アイテムの 2 つの 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とピンポンした後(以下を参照)、質問を次のようなものに言い換えることが提案されました。つまり、$apply を実行しないでください)」これは、Mark が説明したように、ハードコードされた「$apply」を発行し、ダイジェスト ループが実行されるため、「ng-click」自体を使用して回避することはあまり不可能であることを強調するためです。など(以下を参照)

$apply の代わりに $digest を使用する独自のバージョンの ng-click を含む独自の回答を受け入れるため、すべての ng-repeat アイテムの再レンダリングをトリガーしません。

改訂された 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() が表示される理由です。

$watches が変更を検出しない限り、何も再レンダリングされないと思います。

「ページの読み込み時にアイテムごとに2回呼び出される」について:

(変更が検出されると、watchExpression は $digest サイクルごとに複数回実行される可能性があるため、リスナーへの複数回の呼び出しに備えてください。) -- Scope#$watch API doc

@Artem には、Angular のダイジェスト サイクルとダーティ チェックに関する優れた説明があります。要約すると、Angular は最初の $digest サイクルで変更されたものを検出したため、別のサイクルを実行して、すべてのモデルが安定している (変更されていない) ことを確認します。

于 2013-01-30T21:33:20.610 に答える
0

ng-click の代わりに ngp-local-click を試すことができます -> https://github.com/ansukla/ng-perf

于 2014-10-28T17:16:16.463 に答える