Erkennen Sie Änderungen im DOM
-
13-09-2020 - |
Frage
Ich möchte eine Funktion ausführen, wenn dem HTML einige Divs oder Eingaben hinzugefügt werden.Ist das möglich?
Kommt beispielsweise eine Texteingabe hinzu, dann soll die Funktion aufgerufen werden.
Lösung
Update 2015, neu MutationObserver
wird von modernen Browsern unterstützt:
Chrome 18+, Firefox 14+, IE 11+, Safari 6+
Wenn Sie ältere unterstützen müssen, können Sie versuchen, auf andere Ansätze wie die hier genannten zurückzugreifen 5 (!) Jahre alte Antwort unten.Es gibt Drachen.Genießen :)
Jemand anderes ändert das Dokument?Denn wenn Sie die volle Kontrolle über die Änderungen haben, müssen Sie nur noch Ihre eigenen erstellen domChanged
API – mit einer Funktion oder einem benutzerdefinierten Ereignis – und lösen/rufen Sie sie überall dort auf, wo Sie Dinge ändern.
Der DOM Level-2 hat Arten von Mutationsereignissen, aber ältere IE-Versionen unterstützen es nicht.Beachten Sie, dass es sich um Mutationsereignisse handelt in der DOM3-Events-Spezifikation veraltet und habe ein Leistungseinbußen.
Sie können versuchen, ein Mutationsereignis mit zu emulieren onpropertychange
im IE (und auf den Brute-Force-Ansatz zurückgreifen, wenn keiner davon verfügbar ist).
Für ein voll domChange ein Intervall könnte übertrieben sein.Stellen Sie sich vor, Sie müssen den aktuellen Status des gesamten Dokuments speichern und prüfen, ob alle Eigenschaften jedes Elements gleich sind.
Wenn Sie nur an den Elementen und ihrer Reihenfolge interessiert sind (wie Sie in Ihrer Frage erwähnt haben), a getElementsByTagName("*")
kann arbeiten.Dies wird automatisch ausgelöst, wenn Sie ein Element hinzufügen, entfernen, Elemente ersetzen oder die Struktur des Dokuments ändern.
Ich habe einen Proof of Concept geschrieben:
(function (window) {
var last = +new Date();
var delay = 100; // default delay
// Manage event queue
var stack = [];
function callback() {
var now = +new Date();
if (now - last > delay) {
for (var i = 0; i < stack.length; i++) {
stack[i]();
}
last = now;
}
}
// Public interface
var onDomChange = function (fn, newdelay) {
if (newdelay) delay = newdelay;
stack.push(fn);
};
// Naive approach for compatibility
function naive() {
var last = document.getElementsByTagName('*');
var lastlen = last.length;
var timer = setTimeout(function check() {
// get current state of the document
var current = document.getElementsByTagName('*');
var len = current.length;
// if the length is different
// it's fairly obvious
if (len != lastlen) {
// just make sure the loop finishes early
last = [];
}
// go check every element in order
for (var i = 0; i < len; i++) {
if (current[i] !== last[i]) {
callback();
last = current;
lastlen = len;
break;
}
}
// over, and over, and over again
setTimeout(check, delay);
}, delay);
}
//
// Check for mutation events support
//
var support = {};
var el = document.documentElement;
var remain = 3;
// callback for the tests
function decide() {
if (support.DOMNodeInserted) {
window.addEventListener("DOMContentLoaded", function () {
if (support.DOMSubtreeModified) { // for FF 3+, Chrome
el.addEventListener('DOMSubtreeModified', callback, false);
} else { // for FF 2, Safari, Opera 9.6+
el.addEventListener('DOMNodeInserted', callback, false);
el.addEventListener('DOMNodeRemoved', callback, false);
}
}, false);
} else if (document.onpropertychange) { // for IE 5.5+
document.onpropertychange = callback;
} else { // fallback
naive();
}
}
// checks a particular event
function test(event) {
el.addEventListener(event, function fn() {
support[event] = true;
el.removeEventListener(event, fn, false);
if (--remain === 0) decide();
}, false);
}
// attach test events
if (window.addEventListener) {
test('DOMSubtreeModified');
test('DOMNodeInserted');
test('DOMNodeRemoved');
} else {
decide();
}
// do the dummy test
var dummy = document.createElement("div");
el.appendChild(dummy);
el.removeChild(dummy);
// expose
window.onDomChange = onDomChange;
})(window);
Verwendung:
onDomChange(function(){
alert("The Times They Are a-Changin'");
});
Dies funktioniert auf IE 5.5+, FF 2+, Chrome, Safari 3+ und Opera 9.6+
Andere Tipps
Dies ist der ultimative Ansatz bisher mit kleinstem Code:
ie9 +, ff, webkit:
mit mutationobserver und zurück zum veralteten Mutation Events Bei Bedarf:
(Beispiel unten, wenn nur für DOM-Änderungen in Bezug auf angehängte oder entfernte Knoten)
Ich habe kürzlich ein Plugin geschrieben, das genau das tut - jquery.initialize
Sie verwenden es auf die gleiche Weise wie .each
Funktion
$(".some-element").initialize( function(){
$(this).css("color", "blue");
});
Der Unterschied zu .each
ist - in diesem Fall wird Ihr Selektor benötigt .some-element
und warten Sie in Zukunft mit diesem Selektor auf neue Elemente. Wenn ein solches Element hinzugefügt wird, wird es ebenfalls initialisiert.
In unserem Fall ändert die Initialisierungsfunktion einfach die Elementfarbe in Blau.Wenn wir also ein neues Element hinzufügen (egal ob mit Ajax oder sogar F12-Inspektor oder so), wie zum Beispiel:
$("<div/>").addClass('some-element').appendTo("body"); //new element will have blue color!
Das Plugin wird es sofort initiieren.Außerdem stellt das Plugin sicher, dass ein Element nur einmal initialisiert wird.Wenn Sie also ein Element hinzufügen, dann .detach()
Wenn Sie es aus dem Körper entfernen und es dann erneut hinzufügen, wird es nicht erneut initialisiert.
$("<div/>").addClass('some-element').appendTo("body").detach()
.appendTo(".some-container");
//initialized only once
Plugin basiert auf MutationObserver
- Es funktioniert auf IE9 und 10 mit den im Detail aufgeführten Abhängigkeiten Readme-Seite.
oder Sie können einfach Ihr eigenes Ereignis erstellen , das überall ausgeführt wird
generasacodicetagpre.Voller Beispiel http://jsfiddle.net/hbmaam/mq7nx/
Das folgende Beispiel wurde von Mozilla Hacks ' Blog post und verwendet Mutationobserver .
generasacodicetagpre.Browser-Unterstützung: Chrome 18+, Firefox 14+, dh 11+, Safari 6 +
Verwenden Sie den mutationobserver Schnittstelle, wie in Gabriele Romano's
chrom 18+, Firefox 14+, dh 11+, Safari 6 +
generasacodicetagpre.Wie wäre es mit der Erweiterung eines Jquery dafür?
generasacodicetagpre.jQuery 1.9+ hat dazu aufgebaut (ich habe nicht getestet gehört).