Ich möchte eine Funktion ausführen, wenn dem HTML-Code div oder input hinzugefügt werden. Ist das möglich?
Zum Beispiel wird eine Texteingabe hinzugefügt, dann sollte die Funktion aufgerufen werden.
Ich möchte eine Funktion ausführen, wenn dem HTML-Code div oder input hinzugefügt werden. Ist das möglich?
Zum Beispiel wird eine Texteingabe hinzugefügt, dann sollte die Funktion aufgerufen werden.
Antworten:
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 zurückzugreifen, wie die in dieser 5 (!) Jahre alten Antwort unten genannten. Es gibt Drachen. Genießen :)
Jemand anderes ändert das Dokument? Denn wenn Sie die volle Kontrolle über die Änderungen haben, müssen Sie nur Ihre eigene domChanged
API erstellen - mit einer Funktion oder einem benutzerdefinierten Ereignis - und sie überall dort auslösen / aufrufen, wo Sie Dinge ändern.
Das DOM Level-2 verfügt über Mutation-Ereignistypen , ältere Versionen des IE unterstützen dies jedoch nicht. Beachten Sie, dass die Mutationsereignisse in der DOM3-Ereignisspezifikation veraltet sind und eine Leistungsbeeinträchtigung aufweisen .
Sie können versuchen, ein Mutationsereignis mit onpropertychange
im IE zu emulieren (und auf den Brute-Force-Ansatz zurückgreifen, wenn keiner von ihnen verfügbar ist).
Für einen vollständigen domChange kann ein Intervall ein Over-Kill sein. Stellen Sie sich vor, Sie müssen den aktuellen Status des gesamten Dokuments speichern und prüfen, ob jede Eigenschaft jedes Elements gleich ist.
Wenn Sie nur an den Elementen und ihrer Reihenfolge interessiert sind (wie Sie in Ihrer Frage erwähnt haben), getElementsByTagName("*")
kann a möglicherweise funktionieren. Dies wird automatisch ausgelöst, wenn Sie ein Element hinzufügen, ein Element 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 unter IE 5.5+, FF 2+, Chrome, Safari 3+ und Opera 9.6+
IE9 +, FF, Webkit:
Verwenden von MutationObserver und Zurückgreifen auf die veralteten Mutationsereignisse, falls erforderlich:
(Beispiel unten, wenn nur für DOM-Änderungen in Bezug auf angehängte oder entfernte Knoten)
var observeDOM = (function(){
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
return function( obj, callback ){
if( !obj || !obj.nodeType === 1 ) return; // validation
if( MutationObserver ){
// define a new observer
var obs = new MutationObserver(function(mutations, observer){
callback(mutations);
})
// have the observer observe foo for changes in children
obs.observe( obj, { childList:true, subtree:true });
}
else if( window.addEventListener ){
obj.addEventListener('DOMNodeInserted', callback, false);
obj.addEventListener('DOMNodeRemoved', callback, false);
}
}
})();
//------------< DEMO BELOW >----------------
// add item
var itemHTML = "<li><button>list item (click to delete)</button></li>",
listElm = document.querySelector('ol');
document.querySelector('body > button').onclick = function(e){
listElm.insertAdjacentHTML("beforeend", itemHTML);
}
// delete item
listElm.onclick = function(e){
if( e.target.nodeName == "BUTTON" )
e.target.parentNode.parentNode.removeChild(e.target.parentNode);
}
// Observe a specific DOM element:
observeDOM( listElm, function(m){
var addedNodes = [], removedNodes = [];
m.forEach(record => record.addedNodes.length & addedNodes.push(...record.addedNodes))
m.forEach(record => record.removedNodes.length & removedNodes.push(...record.removedNodes))
console.clear();
console.log('Added:', addedNodes, 'Removed:', removedNodes);
});
// Insert 3 DOM nodes at once after 3 seconds
setTimeout(function(){
listElm.removeChild(listElm.lastElementChild);
listElm.insertAdjacentHTML("beforeend", Array(4).join(itemHTML));
}, 3000);
<button>Add Item</button>
<ol>
<li><button>list item (click to delete)</button></li>
<li><button>list item (click to delete)</button></li>
<li><button>list item (click to delete)</button></li>
<li><button>list item (click to delete)</button></li>
<li><em>…More will be added after 3 seconds…</em></li>
</ol>
mutations, observer
Parameter zur besseren Kontrolle an die Rückruffunktion.
Ich habe kürzlich ein Plugin geschrieben, das genau das tut - jquery.initialize
Sie verwenden es genauso wie die .each
Funktion
$(".some-element").initialize( function(){
$(this).css("color", "blue");
});
Der Unterschied zu .each
ist - in diesem Fall ist Ihr Selektor erforderlich.some-element
und in Zukunft mit diesem Selektor auf neue Elemente gewartet wird. Wenn ein solches Element hinzugefügt wird, wird es auch initialisiert.
In unserem Fall ändern Sie die Initialisierungsfunktion einfach die Elementfarbe in Blau. Wenn wir also ein neues Element hinzufügen (egal ob mit Ajax oder sogar F12 Inspector oder so), wie:
$("<div/>").addClass('some-element').appendTo("body"); //new element will have blue color!
Das Plugin wird es sofort starten. Außerdem stellt das Plugin sicher, dass ein Element nur einmal initialisiert wird. Wenn Sie also ein Element hinzufügen, dann.detach()
aus dem Textkörper und dann erneut hinzufügen, wird es nicht erneut initialisiert.
$("<div/>").addClass('some-element').appendTo("body").detach()
.appendTo(".some-container");
//initialized only once
Das Plugin basiert auf MutationObserver
- es funktioniert unter IE9 und 10 mit Abhängigkeiten, wie auf der Readme-Seite beschrieben .
oder Sie können einfach Ihr eigenes Ereignis erstellen , das überall ausgeführt wird
$("body").on("domChanged", function () {
//dom is changed
});
$(".button").click(function () {
//do some change
$("button").append("<span>i am the new change</span>");
//fire event
$("body").trigger("domChanged");
});
Vollständiges Beispiel http://jsfiddle.net/hbmaam/Mq7NX/
Dies ist ein Beispiel für die Verwendung von MutationObserver von Mozilla, angepasst an diesen Blog-Beitrag
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();
Verwenden Sie die MutationObserver- Oberfläche, wie im Blog von Gabriele Romanato gezeigt
Chrome 18+, Firefox 14+, IE 11+, Safari 6+
// The node to be monitored
var target = $( "#content" )[0];
// Create an observer instance
var observer = new MutationObserver(function( mutations ) {
mutations.forEach(function( mutation ) {
var newNodes = mutation.addedNodes; // DOM NodeList
if( newNodes !== null ) { // If there are new nodes added
var $nodes = $( newNodes ); // jQuery set
$nodes.each(function() {
var $node = $( this );
if( $node.hasClass( "message" ) ) {
// do something
}
});
}
});
});
// 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);
// Later, you can stop observing
observer.disconnect();
Wie wäre es damit, eine Abfrage dafür zu erweitern?
(function () {
var ev = new $.Event('remove'),
orig = $.fn.remove;
var evap = new $.Event('append'),
origap = $.fn.append;
$.fn.remove = function () {
$(this).trigger(ev);
return orig.apply(this, arguments);
}
$.fn.append = function () {
$(this).trigger(evap);
return origap.apply(this, arguments);
}
})();
$(document).on('append', function (e) { /*write your logic here*/ });
$(document).on('remove', function (e) { /*write your logic here*/ ) });
Jquery 1.9+ hat Unterstützung dafür aufgebaut (ich habe gehört, nicht getestet).