jQuery-Ereignis: Ermitteln Sie Änderungen am HTML / Text eines Div

265

Ich habe ein div , die ihren Inhalt die ganze Zeit zu ändern hat, sei es ajax requests, jquery functions, bluretc etc.

Gibt es eine Möglichkeit, Änderungen an meinem Div zu jedem Zeitpunkt zu erkennen?

Ich möchte keine Intervalle oder Standardwerte verwenden, die überprüft wurden.

So etwas würde reichen

$('mydiv').contentchanged() {
 alert('changed')
}
BoqBoq
quelle
5
Mögliches Duplikat: stackoverflow.com/questions/10328102/…
Rob
14
@Rob Das bindet ein keypressEreignis an ein inhaltsbearbeitbares <div>Element. Ich bin mir nicht sicher, ob die dortigen Lösungen dafür gelten. Sie würden definitiv keine programmatischen Änderungen am Inhalt eines Elements aufgreifen.
Anthony Grist

Antworten:

406

Wenn Sie keinen Timer verwenden und innerHTML überprüfen möchten, können Sie dieses Ereignis versuchen

$('mydiv').bind('DOMSubtreeModified', function(){
  console.log('changed');
});

Weitere Details und Daten zur Browserunterstützung finden Sie hier .

Achtung: In neueren jQuery-Versionen ist bind () veraltet, daher sollten Sie stattdessen on () verwenden:

$('body').on('DOMSubtreeModified', 'mydiv', function(){
  console.log('changed');
});
Iman
quelle
14
Beachten Sie, dass DOMSubtreeModified in IE8 (und darunter) nicht unterstützt wird.
Gavin
56
Dieses Ereignis ist veraltet w3.org/TR/DOM-Level-3-Events/#glossary-deprecated
Isaiyavan Babu Karan
3
Mozilla 33: Rekursion für Element <body>.
Musste
17
Es ist ernst. Verwenden Sie dieses Ereignis NICHT, da es Ihre gesamte Arbeit zum Absturz bringt, da es ständig ausgelöst wird. Verwenden Sie stattdessen die Ereignisse unter $ ('. MyDiv'). Bind ('DOMNodeInserted DOMNodeRemoved', function () {});
George SEDRA
19
Diese Methode ist veraltet! Verwenden Sie stattdessen:$("body").on('DOMSubtreeModified', "mydiv", function() { });
Asif
55

Verwenden von Javascript MutationObserver

  //More Details https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
 // select the target node
var target = document.querySelector('mydiv')
// create an observer instance
var observer = new MutationObserver(function(mutations) {
  console.log($('mydiv').text());   
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);
PPB
quelle
6
Dies ist die richtige Antwort, da dies jetzt gegenüber der Verwendung von DOMSubtreeModified
Joel Davey
3
Ich erhalte eine Fehlermeldung, obwohl ich den richtigen Selektor angegeben habe. "VM21504: 819 Nicht erfasster Typfehler: Fehler beim Ausführen von'obs 'auf' MutationObserver ': Parameter 1 ist nicht vom Typ' Knoten '."
Samir
54

Da $("#selector").bind()veraltet ist , sollten Sie verwenden:

$("body").on('DOMSubtreeModified', "#selector", function() {
    // code here
});
Petar Nikov
quelle
1
Dies war der Unterscheidungsfaktor, der zusätzlich #anzeigt, dass das Symbol vor dem Selektor stehen muss.
Chris - Jr.
42

Sie können dies versuchen

$('.myDiv').bind('DOMNodeInserted DOMNodeRemoved', function() {

});

Dies funktioniert jedoch möglicherweise nicht im Internet Explorer. Ich habe es nicht getestet

user1790464
quelle
3
HINWEIS!: Wenn Sie dies für einen Auslöser verwenden und viele Änderungen an der Seite vorgenommen werden, wird Ihre Funktion X-mal ausgeführt (möglicherweise sogar X = 1.000 oder mehr), was sehr ineffizient sein kann. Eine einfache Lösung besteht darin, eine "laufende" boolesche Variable zu definieren, die ... if (running == true) {return} ... ohne Ihren Code auszuführen, wenn er bereits ausgeführt wird. Setzen Sie running = true direkt nach Ihrer if-Logik und running = false, bevor Ihre Funktion beendet wird. Sie können auch einen Timer verwenden, um Ihre Funktion so einzuschränken, dass sie nur alle X Sekunden ausgeführt werden kann. running = true; setTimeout (function () {running = false}, 5000); (oder etwas besseres)
JxAxMxIxN
Ich habe dies für ein Auswahlfeld verwendet, in dem Optionen hinzugefügt und entfernt wurden. Es funktionierte großartig, wenn Elemente hinzugefügt wurden, aber das Entfernen schien 1 Element dahinter zu sein. Wenn die letzte Option entfernt wurde, wurde sie nicht ausgelöst.
CodeMonkey
2
@JxAxMxIxN Sie können den Timeout-Timer auch erhöhen, indem Sie das Timeout löschen und erneut einstellen:clearTimeout(window.something); window.something = setTimeout(...);
Strg-C
Einverstanden - Ihr Weg ist der
richtige
33

Sie suchen nach MutationObserver oder Mutation Events . Weder werden sie überall unterstützt noch von der Entwicklerwelt zu gern gesehen.

Wenn Sie wissen (und sicherstellen können, dass sich die Größe des Divs ändert), können Sie möglicherweise das Crossbrowser-Größenänderungsereignis verwenden .

Rodneyrehm
quelle
1
Das ist der eine. Insbesondere DOMSubtreeModified . Möglicherweise finden Sie die Mutationszusammenfassungsbibliothek und diese Liste der DOM -Baumereignisse hilfreich .
BenjaminRH
1
Diese Veranstaltung ist veraltet developer.mozilla.org/en-US/docs/Web/Guide/Events/…
Adrien Be
9
Wenn jemand anderes versuchen musste, alles überall durchzulesen, ist dies die richtige Antwort. Mutationsereignisse wurden in früheren Browsern unterstützt. Mutation Observer wird in modernen Browsern unterstützt und wird in Zukunft unterstützt. Siehe Link für Unterstützung: CANIUSE Mutation Observer
Josh Mc
21

Der folgende Code funktioniert bei mir.

$("body").on('DOMSubtreeModified', "mydiv", function() {
    alert('changed');
});

Hoffe es wird jemandem helfen :)

Sanchit Gupta
quelle
Dies ist die gleiche Antwort wie die von @Artley
Black
@ Schwarz Danke! Ich habe gerade die Artley-Antwort überprüft. Ich werde mich das nächste Mal darum kümmern.
Sanchit Gupta
17

Es gibt keine eingebaute Lösung für dieses Problem. Dies ist ein Problem mit Ihrem Design und Codierungsmuster.

Sie können das Publisher / Subscriber-Muster verwenden. Hierfür können Sie benutzerdefinierte jQuery-Ereignisse oder Ihren eigenen Ereignismechanismus verwenden.

Zuerst,

function changeHtml(selector, html) {
    var elem = $(selector);
    jQuery.event.trigger('htmlchanging', { elements: elem, content: { current: elem.html(), pending: html} });
    elem.html(html);
    jQuery.event.trigger('htmlchanged', { elements: elem, content: html });
}

Jetzt können Sie divhtmlchanging / divhtmlchanged-Ereignisse wie folgt abonnieren:

$(document).bind('htmlchanging', function (e, data) {
    //your before changing html, logic goes here
});

$(document).bind('htmlchanged', function (e, data) {
    //your after changed html, logic goes here
});

Jetzt müssen Sie Ihre Änderungen am Div-Inhalt über diese changeHtml()Funktion ändern . Sie können also die erforderlichen Änderungen entsprechend überwachen oder vornehmen, da das Argument für die Rückrufdatenbindung die Informationen enthält.

Sie müssen das HTML Ihres Divs so ändern;

changeHtml('#mydiv', '<p>test content</p>');

Sie können dies auch für alle HTML-Elemente außer Eingabeelementen verwenden. Auf jeden Fall können Sie dies ändern, um es mit jedem Element zu verwenden.

Sameera Millavithanachchi
quelle
Um Änderungen an einem bestimmten Element zu beobachten und darauf zu reagieren, ändern Sie einfach die Funktion changeHtml, um 'elem.trigger (...)' anstelle von 'jQuery.event.trigger (...)' zu verwenden, und binden Sie dann wie folgt an das Element $ ('# my_element_id'). on ('htmlchanged', Funktion (e, Daten) {...}
KenB
8
"Dies ist ein Problem mit Ihrem Design- und Codierungsmuster". Was tun, wenn Sie Skripte von Drittanbietern einschließen und daher keine Kontrolle über deren Quellcode haben? aber müssen Sie ihre Änderungen an einem div erkennen?
DrLightman
@ DrLightman eine Faustregel ist, Drittanbieter-Bibliothek mit Rückrufereignis zu wählen
Marcel Djaman
8

Verwenden Sie MutationObserver, wie in diesem von Mozilla bereitgestellten und aus diesem Blog-Beitrag adaptierten Snippet zu sehen

Alternativ können Sie das in diesem Link gezeigte JQuery-Beispiel verwenden

Chrome 18+, Firefox 14+, IE 11+, Safari 6+

// Select the node that will be observed for mutations
var targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true };

// Callback function to execute when mutations are observed
var callback = function(mutationsList) {
    for(var mutation of mutationsList) {
        if (mutation.type == 'childList') {
            console.log('A child node has been added or removed.');
        }
        else if (mutation.type == 'attributes') {
            console.log('The ' + mutation.attributeName + ' attribute was modified.');
        }
    }
};

// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

// Later, you can stop observing
observer.disconnect();
Anthony Awuley
quelle
3

Sie können das alte innerHTML des div in einer Variablen speichern. Legen Sie ein Intervall fest, um zu überprüfen, ob der alte Inhalt mit dem aktuellen Inhalt übereinstimmt. Wenn dies nicht stimmt, tu etwas.

codelove
quelle
1

Probieren Sie den MutationObserver aus:

Browserunterstützung: http://caniuse.com/#feat=mutationobserver

<html>
  <!-- example from Microsoft https://developer.microsoft.com/en-us/microsoft-edge/platform/documentation/dev-guide/dom/mutation-observers/ -->

  <head>
    </head>
  <body>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script type="text/javascript">
      // Inspect the array of MutationRecord objects to identify the nature of the change
function mutationObjectCallback(mutationRecordsList) {
  console.log("mutationObjectCallback invoked.");

  mutationRecordsList.forEach(function(mutationRecord) {
    console.log("Type of mutation: " + mutationRecord.type);
    if ("attributes" === mutationRecord.type) {
      console.log("Old attribute value: " + mutationRecord.oldValue);
    }
  });
}
      
// Create an observer object and assign a callback function
var observerObject = new MutationObserver(mutationObjectCallback);

      // the target to watch, this could be #yourUniqueDiv 
      // we use the body to watch for changes
var targetObject = document.body; 
      
// Register the target node to observe and specify which DOM changes to watch
      
      
observerObject.observe(targetObject, { 
  attributes: true,
  attributeFilter: ["id", "dir"],
  attributeOldValue: true,
  childList: true
});

// This will invoke the mutationObjectCallback function (but only after all script in this
// scope has run). For now, it simply queues a MutationRecord object with the change information
targetObject.appendChild(document.createElement('div'));

// Now a second MutationRecord object will be added, this time for an attribute change
targetObject.dir = 'rtl';


      </script>
    </body>
  </html>

juFo
quelle
0

Das Hinzufügen von Inhalten zu einem div, sei es über jQuery oder direkt über die de DOM-API, ist standardmäßig die .appendChild()Funktion. Sie können die .appendChild()Funktion des aktuellen Objekts überschreiben und einen Beobachter darin implementieren. Nachdem .appendChild()wir unsere Funktion überschrieben haben , müssen wir diese Funktion von einem anderen Objekt ausleihen, um den Inhalt anhängen zu können. Deshalb rufen wir das .appendChild()eines anderen Divs an, um den Inhalt endgültig anzuhängen. Dies gilt natürlich auch für die .removeChild().

var obj = document.getElementById("mydiv");
    obj.appendChild = function(node) {
        alert("changed!");

        // call the .appendChild() function of some other div
        // and pass the current (this) to let the function affect it.
        document.createElement("div").appendChild.call(this, node);
        }
    };

Hier finden Sie ein naives Beispiel. Sie können es selbst erweitern, denke ich. http://jsfiddle.net/RKLmA/31/

Übrigens: Dies zeigt, dass JavaScript dem OpenClosed-Prinzip entspricht. :) :)

Andries
quelle
Es funktioniert nicht mit append child ... Ich ändere das HTML tatsächlich über andere Funktionen.
BoqBoq
Wie removeChild () replaceChild () usw. Aber Sie haben Recht mit innerHTML. Du solltest es irgendwie vermeiden.
Andries