Rileva le modifiche nel DOM

Voglio eseguire una funzione quando qualche div o input sono aggiunti all’html. È ansible?

Ad esempio, viene aggiunto un input di testo, quindi è necessario chiamare la funzione.

Aggiornamento 2015, il nuovo MutationObserver è supportato dai browser moderni:

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

Se hai bisogno di supportare quelli più grandi, puoi provare a ricorrere ad altri approcci come quelli menzionati in questa risposta di 5 anni (!) Di seguito. Ci sono draghi. Godere 🙂


Qualcun altro sta cambiando il documento? Perché se hai il pieno controllo sulle modifiche devi solo creare la tua API domChanged – con una funzione o un evento personalizzato – e triggersrla / chiamarla ovunque modifichi le cose.

Il DOM Level-2 ha tipi di eventi Mutation , ma la versione precedente di IE non lo supporta. Si noti che gli eventi di mutazione sono deprecati nella specifica di DOM3 Events e presentano una penalizzazione delle prestazioni .

Puoi provare a emulare l’evento di mutazione con onpropertychange in IE (e onpropertychange brute-force se non è disponibile).

Per una domChange completa un intervallo potrebbe essere un over-kill. Immagina di aver bisogno di memorizzare lo stato corrente dell’intero documento ed esaminare ogni proprietà di ogni elemento per essere uguale.

Forse se sei interessato solo agli elementi e al loro ordine (come hai detto nella tua domanda), un getElementsByTagName("*") può funzionare. Questo si triggers automaticamente se aggiungi un elemento, rimuovi un elemento, sostituisci elementi o cambia la struttura del documento.

Ho scritto una prova di concetto:

 (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); 

Uso:

 onDomChange(function(){ alert("The Times They Are a-Changin'"); }); 

Funziona su IE 5.5+, FF 2+, Chrome, Safari 3+ e Opera 9.6+

Questo è l’ultimo approccio finora, con il codice più piccolo:

IE9 +, FF, Webkit:

Utilizzo di MutationObserver e ritorno agli eventi di Mutazione deprecati , se necessario:
(Esempio di seguito se solo per modifiche DOM relative ai nodes aggiunti o rimossi)

 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){ if( mutations[0].addedNodes.length || mutations[0].removedNodes.length ) callback( mutations[0] ); }); // 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 document.querySelector('body > button').onclick = function(e){ var newElmHTML = "
  • "; document.querySelector('ol').insertAdjacentHTML("beforeend", newElmHTML); } // delete item document.querySelector('ol').onclick = function(e){ if( e.target.nodeName == "BUTTON" ) e.target.parentNode.parentNode.removeChild(e.target.parentNode); } // Observe a specific DOM element: observeDOM( document.querySelector('ol'), function(m){ console.clear(); console.log('Added:', m.addedNodes, 'Removed:', m.removedNodes); });
      

    Recentemente ho scritto un plugin che fa esattamente questo – jquery.initialize

    Lo usi allo stesso modo della funzione .each

     $(".some-element").initialize( function(){ $(this).css("color", "blue"); }); 

    La differenza da .each è: in questo caso, seleziona il tuo selettore e attende i nuovi elementi con questo selettore in futuro, se tale elemento verrà aggiunto verrà anch’esso inizializzato.

    Nel nostro caso, la funzione di inizializzazione cambia semplicemente il colore dell’elemento in blu. Quindi, se aggiungiamo un nuovo elemento (non importa se con ajax o persino un ispettore F12 o altro) come:

     $("
    ").addClass('some-element').appendTo("body"); //new element will have blue color!

    Il plug-in inizierà immediatamente. Inoltre il plugin si assicura che un elemento sia inizializzato solo una volta. Quindi se aggiungi un elemento, poi .detach() dal corpo e poi lo aggiungi di nuovo, non verrà nuovamente inizializzato.

     $("
    ").addClass('some-element').appendTo("body").detach() .appendTo(".some-container"); //initialized only once

    Il plugin è basato su MutationObserver – funzionerà su IE9 e 10 con dipendenze come dettagliato nella pagina readme .

    oppure puoi semplicemente creare il tuo evento , che funziona ovunque

      $("body").on("domChanged", function () { //dom is changed }); $(".button").click(function () { //do some change $("button").append("i am the new change"); //fire event $("body").trigger("domChanged"); }); 

    Esempio completo http://jsfiddle.net/hbmaam/Mq7NX/

    Questo è un esempio che utilizza MutationObserver di Mozilla adattato da questo post del blog

    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(); 

    Che ne dici di estendere un jquery per questo?

      (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+ ha sviluppato il supporto per questo (ho sentito non testato).

    Usa JQuery MutationObserver come mostrato nel blog di Gabriele Romanato

    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();