1675 Stimmen

Ereignisbindung bei dynamisch erstellten Elementen?

Ich habe ein bisschen Code, wo ich bin Schleife durch alle Auswahlfelder auf einer Seite und Bindung einer .hover Ereignis an sie, um ein wenig an ihrer Breite zu schrauben mouse on/off .

Dies geschieht, sobald die Seite fertig ist und funktioniert einwandfrei.

Das Problem, das ich habe, ist, dass alle Auswahlfelder, die ich über Ajax oder DOM nach der ersten Schleife hinzufügen, nicht das Ereignis gebunden haben.

Ich habe dieses Plugin gefunden ( jQuery Live Query Plugin ), aber bevor ich ein weiteres 5k zu meinen Seiten mit einem Plugin hinzufügen, möchte ich sehen, ob jemand einen Weg kennt, dies zu tun, entweder mit jQuery direkt oder durch eine andere Option.

2570voto

dev.e.loper Punkte 34942

Ab jQuery 1.7 sollten Sie jQuery.fn.on mit dem gefüllten Selektorparameter:

$(staticAncestors).on(eventName, dynamicChild, function() {});

Erläuterung:

Dies wird als Ereignisdelegation bezeichnet und funktioniert wie folgt. Das Ereignis wird an ein statisches übergeordnetes Ereignis ( staticAncestors ) des Elements, das behandelt werden soll. Dieser jQuery-Handler wird jedes Mal ausgelöst, wenn das Ereignis auf diesem Element oder einem der nachgeordneten Elemente ausgelöst wird. Der Handler prüft dann, ob das Element, das das Ereignis ausgelöst hat, mit Ihrem Selektor ( dynamicChild ). Wenn es eine Übereinstimmung gibt, wird Ihre benutzerdefinierte Handler-Funktion ausgeführt.


Vor diesem Zeitpunkt wurde empfohlen, die folgende Methode zu verwenden live() :

$(selector).live( eventName, function(){} );

Allerdings, live() wurde in 1.7 zugunsten von on() und in 1.9 vollständig entfernt. Die live() Unterschrift:

$(selector).live( eventName, function(){} );

... kann durch Folgendes ersetzt werden on() Unterschrift:

$(document).on( eventName, selector, function(){} );

Wenn Ihre Seite zum Beispiel dynamisch Elemente mit dem Klassennamen dosomething würden Sie das Ereignis an ein bereits existierendes Elternteil (dies ist der Kern des Problems hier, Sie brauchen etwas, das existiert, um zu binden, binden Sie nicht an den dynamischen Inhalt), dies kann sein (und die einfachste Option) ist document . Bedenken Sie jedoch, dass document möglicherweise nicht die effizienteste Option ist .

$(document).on('mouseover mouseout', '.dosomething', function(){
    // what you want to happen when mouseover and mouseout 
    // occurs on elements that match '.dosomething'
});

Jedes Elternteil, das zum Zeitpunkt der Bindung des Ereignisses existiert, ist in Ordnung. Zum Beispiel

$('.buttons').on('click', 'button', function(){
    // do something here
});

würde gelten für

<div class="buttons">
    <!-- <button>s that are generated dynamically and added here -->
</div>

58 Stimmen

Erfahren Sie hier mehr über die Delegation von Veranstaltungen: learn.jquery.com/events/ereignis-delegation .

0 Stimmen

Diese Lösung führt immer noch zu Fehlern in jQuery 3 und Firefox, da nach dem Löschen von html und der Neuerstellung das Ereignis zweimal ausgelöst wird,

3 Stimmen

In dieser Lösung wird "Ereignisdelegation" zwar mindestens zehnmal erwähnt, aber nirgends wird gezeigt, wie man ein Ereignis an eine dynamisch gebundene Funktion delegiert.

422voto

Ronen Rabinovici Punkte 7908

Eine gute Erklärung findet sich in der Dokumentation von jQuery.fn.on .

Kurz gesagt:

Ereignishandler sind nur an die aktuell ausgewählten Elemente gebunden; sie müssen auf der Seite zu dem Zeitpunkt vorhanden sein, zu dem Ihr Code den Aufruf von .on() .

In folgendem Beispiel #dataTable tbody tr muss vorhanden sein, bevor der Code generiert wird.

$("#dataTable tbody tr").on("click", function(event){
    console.log($(this).text());
});

Wenn neues HTML in die Seite eingefügt wird, ist es besser, delegierte Ereignisse zu verwenden, um einen Event-Handler anzuhängen, wie im Folgenden beschrieben.

Delegierte Ereignisse haben den Vorteil, dass sie Ereignisse von Nachfahrenelementen verarbeiten können, die dem Dokument zu einem späteren Zeitpunkt hinzugefügt werden. Wenn z. B. die Tabelle existiert, aber die Zeilen dynamisch mit Hilfe von Code hinzugefügt werden, wird dies wie folgt gehandhabt:

$("#dataTable tbody").on("click", "tr", function(event){
    console.log($(this).text());
});

Ein weiterer Vorteil delegierter Ereignisse besteht darin, dass sie nicht nur Ereignisse für nachgeordnete Elemente verarbeiten können, die noch nicht erstellt wurden, sondern auch einen wesentlich geringeren Overhead verursachen, wenn viele Elemente überwacht werden müssen. Bei einer Datentabelle mit 1.000 Zeilen in ihrer tbody Im ersten Codebeispiel wird ein Handler an 1.000 Elemente angehängt.

Bei einem Ansatz mit delegierten Ereignissen (zweites Codebeispiel) wird ein Ereignishandler nur an ein Element, das tbody und das Ereignis muss nur eine Ebene nach oben gehen (vom angeklickten tr zu tbody ).

Nota: Delegierte Ereignisse funktionieren nicht bei SVG .

288voto

Ram Patra Punkte 15496

Dies ist eine reines JavaScript Lösung ohne jegliche Bibliotheken oder Plugins:

document.addEventListener('click', function (e) {
    if (hasClass(e.target, 'bu')) {
        // .bu clicked
        // Do your thing
    } else if (hasClass(e.target, 'test')) {
        // .test clicked
        // Do your other thing
    }
}, false);

wobei hasClass es

function hasClass(elem, className) {
    return elem.className.split(' ').indexOf(className) > -1;
}

<strong><a href="http://jsfiddle.net/ramswaroop/Nrxp5/28/" rel="noreferrer">Live demo</a></strong>

Der Dank geht an Dave und Sime Vidas

Verwendung modernerer JS, hasClass kann als implementiert werden:

function hasClass(elem, className) {
    return elem.classList.contains(className);
}

Die gleiche jsfiddle Live-Demo ist unten eingebettet:

function hasClass(elem, className) {
  return elem.classList.contains(className);
}

document.addEventListener('click', function(e) {
  if (hasClass(e.target, 'bu')) {
    alert('bu');
    document.querySelector('.bu').innerHTML = '<div class="bu">Bu<div class="tu">Tu</div></div>';
  } else if (hasClass(e.target, 'test')) {
    alert('test');
  } else if (hasClass(e.target, 'tu')) {
    alert('tu');
  }

}, false);

.test,
.bu,
.tu {
  border: 1px solid gray;
  padding: 10px;
  margin: 10px;
}

<div class="test">Test
  <div class="bu">Bu</div>test
</div>

5 Stimmen

12 Stimmen

Sie können verwenden Element.classList anstatt zu splitten

2 Stimmen

@EugenKonkov Element.classList wird bei älteren Browsern nicht unterstützt. Zum Beispiel, IE < 9.

85voto

nickf Punkte 517253

Bei der Erstellung von Objekten können Sie ihnen Ereignisse hinzufügen. Wenn Sie mehreren Objekten zu verschiedenen Zeitpunkten dieselben Ereignisse hinzufügen möchten, ist die Erstellung einer benannten Funktion möglicherweise die beste Lösung.

var mouseOverHandler = function() {
    // Do stuff
};
var mouseOutHandler = function () {
    // Do stuff
};

$(function() {
    // On the document load, apply to existing elements
    $('select').hover(mouseOverHandler, mouseOutHandler);
});

// This next part would be in the callback from your Ajax call
$("<select></select>")
    .append( /* Your <option>s */ )
    .hover(mouseOverHandler, mouseOutHandler)
    .appendTo( /* Wherever you need the select box */ )
;

57voto

Greg Borenstein Punkte 1476

Sie könnten einfach Ihren Ereignisbindungsaufruf in eine Funktion verpacken und diese dann zweimal aufrufen: einmal bei Dokument bereit und einmal nach Ihrem Ereignis, das die neuen DOM-Elemente hinzufügt. Wenn Sie das tun, wollen Sie vermeiden, dass das gleiche Ereignis zweimal auf die bestehenden Elemente zu binden, so müssen Sie entweder unbind die bestehenden Ereignisse oder (besser) nur binden, um die DOM-Elemente, die neu erstellt werden. Der Code würde etwa so aussehen:

function addCallbacks(eles){
    eles.hover(function(){alert("gotcha!")});
}

$(document).ready(function(){
    addCallbacks($(".myEles"))
});

// ... add elements ...
addCallbacks($(".myNewElements"))

2 Stimmen

Dieser Beitrag hat mir wirklich geholfen, ein Problem in den Griff zu bekommen, das ich beim Laden des gleichen Formulars hatte und 1,2,4,8,16... Übermittlungen erhielt. Anstatt .live() zu verwenden, habe ich einfach .bind() in meinem .load() Callback verwendet. Das Problem ist gelöst. Vielen Dank!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X