Esiste un listener di modifiche DOM JavaScript / jQuery?


402

In sostanza, voglio che uno script venga eseguito quando il contenuto di una DIVmodifica. Poiché gli script sono separati (script di contenuto nell'estensione di Chrome e script di pagine Web), ho bisogno di un modo per osservare semplicemente i cambiamenti nello stato DOM. Potrei impostare il polling ma questo sembra sciatto.

Risposte:


488

Per molto tempo, gli eventi di mutazione DOM3 sono stati la migliore soluzione disponibile, ma sono stati deprecati per motivi di prestazioni. Gli osservatori di mutazione DOM4 sostituiscono gli eventi di mutazione DOM3 deprecati. Attualmente sono implementati nei browser moderni come MutationObserver(o come prefisso fornitore WebKitMutationObservernelle vecchie versioni di Chrome):

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var observer = new MutationObserver(function(mutations, observer) {
    // fired when a mutation occurs
    console.log(mutations, observer);
    // ...
});

// define what element should be observed by the observer
// and what types of mutations trigger the callback
observer.observe(document, {
  subtree: true,
  attributes: true
  //...
});

Questo esempio ascolta le modifiche del DOM su documente la sua intera sottostruttura e si attiverà sia sulle modifiche agli attributi degli elementi sia su modifiche strutturali. La bozza delle specifiche ha un elenco completo delle proprietà valide del listener di mutazione :

childList

  • Impostare su truese si devono osservare mutazioni ai figli del bersaglio.

attributi

  • Impostare su truese si devono osservare mutazioni agli attributi del bersaglio.

CharacterData

  • Impostare su truese si devono osservare mutazioni ai dati del bersaglio.

sottostruttura

  • Impostare su truese le mutazioni non devono solo essere bersaglio, ma anche i discendenti del bersaglio.

attributeOldValue

  • Impostato su trueif attributesè impostato su true e sul valore dell'attributo target prima che la mutazione debba essere registrata.

characterDataOldValue

  • Impostato su trueif characterDataè impostato su true e i dati del target prima che la mutazione debba essere registrata.

attributeFilter

  • Impostare su un elenco di nomi locali di attributi (senza spazio dei nomi) se non è necessario osservare tutte le mutazioni degli attributi.

(Questo elenco è aggiornato ad aprile 2014; è possibile verificare le specifiche per eventuali modifiche.)


3
@AshrafBashir Vedo l'esempio che funziona bene in Firefox 19.0.2: vedo ([{}])registrato sulla console, che mostra l'atteso MutationRecordquando faccio clic su di esso. Ricontrolla, poiché potrebbe essersi verificato un errore tecnico temporaneo in JSFiddle. Non l'ho ancora testato in IE, dal momento che non ho IE 10, che è attualmente l'unica versione a supportare gli eventi di mutazione.
apsillers

1
Ho appena pubblicato una risposta che funziona in IE10 + e soprattutto qualsiasi altra cosa.
naugtur

1
La specifica non sembra avere una casella verde che elenca più le opzioni dell'osservatore di mutazione. Lo fa la lista delle opzioni nella sezione 5.3.1 e descrive loro solo un po 'più sotto di quella.
LS

2
@LS Grazie, ho aggiornato il link, rimosso il bit relativo alla casella verde e modificato l'intero elenco nella mia risposta (solo in caso di futuro marcio del link).
apsillers


211

modificare

Questa risposta è ora obsoleta. Vedi la risposta di apsillers .

Poiché questo è per un'estensione di Chrome, potresti anche utilizzare l'evento DOM standard - DOMSubtreeModified. Consulta il supporto per questo evento nei browser. È supportato in Chrome dalla 1.0.

$("#someDiv").bind("DOMSubtreeModified", function() {
    alert("tree changed");
});

Vedi un esempio funzionante qui .


Ho notato che questo evento può essere attivato anche dopo determinati selettori. Sto attualmente indagando.
Peder Rice,

9
w3.org/TR/DOM-Level-3-Events/#event-type-DOMSubtreeModified afferma che questo evento è deprecato, che cosa utilizzeremmo invece?
Maslow,


4
C'è github.com/joelpurra/jquery-mutation-summary che sostanzialmente lo risolve per gli utenti jquery.
Capi Etheriel,

1
Funziona ancora se stai sviluppando estensioni di Chrome. inestimabile.
concept47

49

Molti siti utilizzano AJAX per aggiungere / mostrare / modificare i contenuti in modo dinamico. A volte viene utilizzato al posto della navigazione in-site, quindi l'URL corrente viene modificato a livello di codice e gli script di contenuto non vengono automaticamente eseguiti dal browser in questo caso poiché la pagina non viene recuperata interamente dal server remoto.


Metodi usuali di JS per rilevare le modifiche alla pagina disponibili in uno script di contenuto .


Specifico per le estensioni: rileva le modifiche agli URL in una pagina di sfondo / evento .

Esistono API avanzate per lavorare con la navigazione: webNavigation , webRequest , ma utilizzeremo un semplice listener di eventi chrome.tabs.onUpdated che invia un messaggio allo script del contenuto:

  • manifest.json:
    dichiara la pagina in background / evento
    dichiara l' autorizzazione per aggiungere lo script di contenuto .
    "tabs"

  • background.js

    var rxLookfor = /^https?:\/\/(www\.)?google\.(com|\w\w(\.\w\w)?)\/.*?[?#&]q=/;
    chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
        if (rxLookfor.test(changeInfo.url)) {
            chrome.tabs.sendMessage(tabId, 'url-update');
        }
    });
  • content.js

    chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
        if (msg === 'url-update') {
            doSomething();
        }
    });

29

Un altro approccio a seconda di come stai cambiando il div. Se si utilizza JQuery per modificare il contenuto di un div con il suo metodo html (), è possibile estendere quel metodo e chiamare una funzione di registrazione ogni volta che si inserisce html in un div.

(function( $, oldHtmlMethod ){
    // Override the core html method in the jQuery object.
    $.fn.html = function(){
        // Execute the original HTML method using the
        // augmented arguments collection.

        var results = oldHtmlMethod.apply( this, arguments );
        com.invisibility.elements.findAndRegisterElements(this);
        return results;

    };
})( jQuery, jQuery.fn.html );

Intercettiamo semplicemente le chiamate a html (), chiamiamo una funzione di registrazione con questa, che nel contesto si riferisce all'elemento target che ottiene nuovi contenuti, quindi passiamo la chiamata alla funzione originale jquery.html (). Ricorda di restituire i risultati del metodo html () originale, poiché JQuery si aspetta che venga concatenato il metodo.

Per ulteriori informazioni sulla sostituzione e l'estensione del metodo, consultare http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm , che è dove Ho paralizzato la funzione di chiusura. Dai un'occhiata anche al tutorial dei plugin sul sito di JQuery.


7

Oltre agli strumenti "grezzi" forniti MutationObserverdall'API , esistono librerie "convenienti" per lavorare con le mutazioni DOM.

Considerare: MutationObserver rappresenta ogni modifica DOM in termini di sottotitoli. Quindi, se, ad esempio, stai aspettando che un certo elemento venga inserito, potrebbe essere nel profondo dei figli dimutations.mutation[i].addedNodes[j] .

Un altro problema è quando il tuo codice, in reazione alle mutazioni, cambia DOM - spesso vuoi filtrarlo.

Una buona libreria di convenienza che risolve tali problemi è mutation-summary (dichiarazione di non responsabilità: non sono l'autore, solo un utente soddisfatto), che ti consente di specificare le domande su ciò che ti interessa e ottenere esattamente questo.

Esempio di utilizzo di base dai documenti:

var observer = new MutationSummary({
  callback: updateWidgets,
  queries: [{
    element: '[data-widget]'
  }]
});

function updateWidgets(summaries) {
  var widgetSummary = summaries[0];
  widgetSummary.added.forEach(buildNewWidget);
  widgetSummary.removed.forEach(cleanupExistingWidget);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.