Weisen Sie Click-Handler in der for-Schleife zu


74

Ich habe mehrere divs #mydiv1, #mydiv2, #mydiv3, ... und wollen assign Klick - Handler zu ihnen:

$(document).ready(function(){
  for(var i = 0; i < 20; i++) {
    $('#question' + i).click( function(){
      alert('you clicked ' + i);
    });
  }
});

Aber anstatt zu zeigen, 'you clicked 3'wann #mydiv3ich klicke (wie bei jedem anderen Klick), bekomme ich 'you clicked 20'. Was mache ich falsch?

Antworten:


135

Es ist ein häufiger Fehler, in Javascript Verschlüsse in Schleifen zu erstellen . Sie benötigen eine Rückruffunktion wie diese:

function createCallback( i ){
  return function(){
    alert('you clicked' + i);
  }
}

$(document).ready(function(){
  for(var i = 0; i < 20; i++) {
    $('#question' + i).click( createCallback( i ) );
  }
});

Update 3. Juni 2016: Da diese Frage immer noch an Bedeutung gewinnt und auch ES6 immer beliebter wird, würde ich eine moderne Lösung vorschlagen. Wenn Sie ES6 schreiben, können Sie das letSchlüsselwort verwenden, mit dem die iVariable lokal in der Schleife anstatt global ist:

for(let i = 0; i < 20; i++) {
  $('#question' + i).click( function(){
    alert('you clicked ' + i);
  });
}

Es ist kürzer und leichter zu verstehen.


7
Eigentlich sollte zur Erklärung geschrieben werden, dass die anonyme Funktion, die auf "i" verweist, nur im Kontext der Schleife ausgeführt wird und nicht sofort ausgeführt wird. Das heißt, wenn das Ereignis onclick eintritt, befindet sich "i" tatsächlich am Endzustand der Schleife. Sie können dies umgehen, indem Sie "i" als lokalen Parameter übergeben (wie dies bei dieser Rückruflösung der Fall ist).
Hurikhan77

3
Ich würde wirklich nicht callback"Rückruf" nennen. Es ist kein Rückruf. Es ist eine Fabrik zum Erstellen von Rückrufen.
TJ Crowder

Wirklich nützliche Antwort. Hatte auch dieses Problem und konnte Ihre Lösung so ändern, dass bei jedem Durchlauf der Schleife ein Bindungsklickereignis erstellt wird.
Ian

es wird immer zwanzig sein. verursacht durch clientseitiges Inkrement.
de_nuit

12

Zur Verdeutlichung ist i gleich 20, da das Klickereignis erst nach Beendigung der Schleife ausgelöst wurde.


7
$(document).ready(function(){
  for(var i = 0; i < 5; i++) {
   var $li= $('<li>' + i +'</li>');
      (function(i) {
           $li.click( function(){
           alert('you clicked ' + i);
         });
      }(i));
      $('#ul').append($li);
  }
});

Das Durchlaufen einer anonymen Funktion funktioniert für mich besser
Vad

6

Mit on zum Anhängen des Klick-Handlers können Sie die Ereignisdaten verwenden, um Ihre Daten wie folgt zu übergeben:

for(var i = 0; i < 20; i++) {
  $('#question' + i).on('click', {'idx': i}, function(e) {
    alert('you clicked ' + e.data.idx);
  });
}


4

Sie können damit auskommen, den Klick-Handler einmal zuzuweisen (oder zumindest nicht viele unnötige Schließungen vorzunehmen). Setzen Sie alle Divs in eine Klasse mydivs, dann:

$(document).ready(function(){
    $('.mydivs').click(function(){
        // Get the number starting from the ID's 6th character
        // This assumes that the common prefix is "mydiv"
        var i = Number(this.id.slice(5));

        alert('you clicked ' + i);
    });
});

Dabei wird die ID des Elements überprüft, um seine Nummer zu erhalten. Dabei werden die Anfangsbuchstaben mithilfe der sliceZeichenfolgenmethode entfernt.

Hinweis: Es ist möglicherweise besser zu verwenden

$('#divcontainer').on('click', '.mydivs', function(){

anstatt

$('.mydivs').click(function(){

2

Wenn Sie einer großen Anzahl von Elementen Klick-Handles zuweisen möchten, benötigen Sie im Allgemeinen einen Container (Div auf höherer Ebene), der die Klicks für Sie interpretiert, da der Klick aus dem Dom sprudelt.

<div id="bucket">
    <span class="decorator-class" value="3">
    ...
</div>

<script>
   $(document).ready(function(e){
      $("#bucket").live('click', function(){
         if(e.target).is('span'){
            alert("elementid: " + $(e.target).val());
         }
      }
   }
<script>
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.