Existe-t-il un écouteur de changement DOM JavaScript / jQuery?
402
Essentiellement, je veux qu'un script s'exécute lorsque le contenu d'un DIVchangement. Étant donné que les scripts sont séparés (script de contenu dans l'extension Chrome et le script de page Web), j'ai besoin d'un moyen simplement d'observer les changements dans l'état DOM. Je pourrais mettre en place un sondage mais cela semble bâclé.
Pendant longtemps, les événements de mutation DOM3 étaient la meilleure solution disponible, mais ils ont été déconseillés pour des raisons de performances. Les observateurs de mutation DOM4 remplacent les événements de mutation DOM3 obsolètes. Ils sont actuellement implémentés dans les navigateurs modernes comme MutationObserver(ou comme préfixés par le fournisseur WebKitMutationObserverdans les anciennes versions de Chrome):
MutationObserver= window.MutationObserver|| window.WebKitMutationObserver;var observer =newMutationObserver(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//...});
Cet exemple écoute les modifications DOM sur documentet toute sa sous-arborescence, et il se déclenche sur les modifications apportées aux attributs d'élément ainsi que les modifications structurelles. Le projet de spécification contient une liste complète des propriétés d'écouteur de mutation valides :
childList
Définissez truesi des mutations sur les enfants de la cible doivent être observées.
les attributs
Définissez truesi des mutations des attributs de la cible doivent être observées.
characterData
Définissez truesi des mutations des données de la cible doivent être observées.
sous-arbre
Définissez truesi les mutations non seulement pour la cible, mais aussi pour les descendants de la cible doivent être observées.
attributeOldValue
La valeur trueif attributesest définie sur true et la valeur d'attribut de la cible avant que la mutation ne soit enregistrée.
characterDataOldValue
Défini sur trueif characterDataest défini sur true et les données de la cible avant que la mutation ne soit enregistrée.
attributeFilter
Définissez une liste de noms locaux d'attributs (sans espace de noms) si toutes les mutations d'attributs ne doivent pas être observées.
(Cette liste est à jour en avril 2014; vous pouvez vérifier les spécifications pour tout changement.)
@AshrafBashir Je vois que l'échantillon fonctionne correctement dans Firefox 19.0.2: je vois que je suis ([{}])connecté à la console, ce qui montre ce qui est attendu MutationRecordlorsque je clique dessus. Veuillez vérifier à nouveau, car il pourrait s'agir d'une défaillance technique temporaire dans JSFiddle. Je ne l'ai pas encore testé dans IE, car je n'ai pas IE 10, qui est actuellement la seule version à prendre en charge les événements de mutation.
apsillers
1
Je viens de publier une réponse qui fonctionne dans IE10 + et surtout n'importe quoi d'autre.
naugtur
1
La spécification ne semble pas avoir de boîte verte qui répertorie plus les options d'observateur de mutation. Il énumère les options de la section 5.3.1 et les décrit juste un peu plus loin.
LS
2
@LS Merci, j'ai mis à jour le lien, supprimé le bit sur la boîte verte et édité toute la liste dans ma réponse (juste en cas de future pourriture du lien).
Cette réponse est désormais obsolète. Voir la réponse des apsillers .
Comme il s'agit d'une extension Chrome, vous pouvez tout aussi bien utiliser l'événement DOM standard - DOMSubtreeModified. Voir le support de cet événement sur tous les navigateurs. Il est pris en charge dans Chrome depuis 1.0.
Fonctionne toujours si vous créez des extensions Chrome. inestimable.
concept47
49
De nombreux sites utilisent AJAX pour ajouter / afficher / modifier le contenu de manière dynamique. Parfois, il est utilisé à la place de la navigation sur site, donc l'URL actuelle est modifiée par programme et les scripts de contenu ne sont pas automatiquement exécutés par le navigateur dans ce cas, car la page n'est pas entièrement récupérée du serveur distant.
Méthodes JS habituelles de détection des modifications de page disponibles dans un script de contenu .
MutationObserver ( docs ) pour détecter littéralement les changements DOM:
Vérification périodique du DOM via setInterval :
Évidemment, cela ne fonctionnera que dans les cas où vous attendez qu'un élément spécifique identifié par son identifiant / sélecteur apparaisse, et il ne vous permettra pas de détecter universellement le nouveau contenu ajouté dynamiquement à moins que vous n'inventiez une sorte d'empreinte digitale le contenu existant.
document.head.appendChild(document.createElement('script')).text ='('+function(){// injected DOM script is not a content script anymore, // it can modify objects and functions of the pagevar _pushState = history.pushState;
history.pushState =function(state, title, url){
_pushState.call(this, state, title, url);
window.dispatchEvent(newCustomEvent('state-changed',{detail: state}));};// repeat the above for replaceState too}+')(); this.remove();';// remove the DOM script element// And here content script listens to our DOM script custom events
window.addEventListener('state-changed',function(e){
console.log('History state changed', e.detail, location.hash);
doSomething();});
Une autre approche selon la façon dont vous changez le div. Si vous utilisez JQuery pour modifier le contenu d'un div avec sa méthode html (), vous pouvez étendre cette méthode et appeler une fonction d'enregistrement chaque fois que vous mettez du html dans 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 );
Nous interceptons simplement les appels à html (), appelons une fonction d'enregistrement avec cela, qui dans le contexte fait référence à l'élément cible obtenant un nouveau contenu, puis nous passons l'appel à la fonction jquery.html () d'origine. N'oubliez pas de renvoyer les résultats de la méthode html () d'origine, car JQuery l'attend pour le chaînage de méthode.
En plus des outils "bruts" fournis par l' MutationObserverAPI , il existe des bibliothèques "pratiques" pour travailler avec les mutations DOM.
Considérez: MutationObserver représente chaque changement DOM en termes de sous-arbres. Donc, si vous attendez, par exemple, qu'un certain élément soit inséré, il peut être au plus profond des enfants de mutations.mutation[i].addedNodes[j].
Un autre problème est lorsque votre propre code, en réaction aux mutations, change de DOM - vous voulez souvent le filtrer.
Une bonne bibliothèque pratique qui résout ces problèmes est mutation-summary(avertissement: je ne suis pas l'auteur, juste un utilisateur satisfait), qui vous permet de spécifier des requêtes de ce qui vous intéresse et d'obtenir exactement cela.
([{}])
connecté à la console, ce qui montre ce qui est attenduMutationRecord
lorsque je clique dessus. Veuillez vérifier à nouveau, car il pourrait s'agir d'une défaillance technique temporaire dans JSFiddle. Je ne l'ai pas encore testé dans IE, car je n'ai pas IE 10, qui est actuellement la seule version à prendre en charge les événements de mutation.Éditer
Cette réponse est désormais obsolète. Voir la réponse des apsillers .
Comme il s'agit d'une extension Chrome, vous pouvez tout aussi bien utiliser l'événement DOM standard -
DOMSubtreeModified
. Voir le support de cet événement sur tous les navigateurs. Il est pris en charge dans Chrome depuis 1.0.Voir un exemple de travail ici .
la source
De nombreux sites utilisent AJAX pour ajouter / afficher / modifier le contenu de manière dynamique. Parfois, il est utilisé à la place de la navigation sur site, donc l'URL actuelle est modifiée par programme et les scripts de contenu ne sont pas automatiquement exécutés par le navigateur dans ce cas, car la page n'est pas entièrement récupérée du serveur distant.
Méthodes JS habituelles de détection des modifications de page disponibles dans un script de contenu .
MutationObserver ( docs ) pour détecter littéralement les changements DOM:
Écouteur d'événements pour les sites qui signalent un changement de contenu en envoyant un événement DOM:
pjax:end
surdocument
utilisé par de nombreux sites basés sur pjax, par exemple GitHub,voir Comment exécuter jQuery avant et après une charge pjax?
message
surwindow
utilisé par exemple Google recherche dans le navigateur Chrome,voir extension Chrome détecter recherche Google Actualiser
spfdone
surdocument
utilisé par Youtube,voir Comment détecter la navigation de page sur Youtube et modifier le HTML avant le rendu de la page?
Vérification périodique du DOM via setInterval :
Évidemment, cela ne fonctionnera que dans les cas où vous attendez qu'un élément spécifique identifié par son identifiant / sélecteur apparaisse, et il ne vous permettra pas de détecter universellement le nouveau contenu ajouté dynamiquement à moins que vous n'inventiez une sorte d'empreinte digitale le contenu existant.
API d'historique de masquage à l' intérieur d'un script DOM injecté :
Écoute de hashchange , événements popstate :
Spécifique aux extensions: détecte les changements d'URL dans une page d' arrière - plan / événement .
Il existe des API avancées pour travailler avec la navigation: webNavigation , webRequest , mais nous utiliserons un simple écouteur d'événements chrome.tabs.onUpdated qui envoie un message au script de contenu:
manifest.json:
déclarer la page d'arrière-plan / événement
déclarer l' autorisation d' ajouter un script de contenu .
"tabs"
background.js
content.js
la source
Une autre approche selon la façon dont vous changez le div. Si vous utilisez JQuery pour modifier le contenu d'un div avec sa méthode html (), vous pouvez étendre cette méthode et appeler une fonction d'enregistrement chaque fois que vous mettez du html dans un div.
Nous interceptons simplement les appels à html (), appelons une fonction d'enregistrement avec cela, qui dans le contexte fait référence à l'élément cible obtenant un nouveau contenu, puis nous passons l'appel à la fonction jquery.html () d'origine. N'oubliez pas de renvoyer les résultats de la méthode html () d'origine, car JQuery l'attend pour le chaînage de méthode.
Pour plus d'informations sur la substitution et l'extension de méthode, consultez http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm , qui est l'endroit où J'ai bercé la fonction de fermeture. Consultez également le tutoriel des plugins sur le site de JQuery.
la source
En plus des outils "bruts" fournis par l'
MutationObserver
API , il existe des bibliothèques "pratiques" pour travailler avec les mutations DOM.Considérez: MutationObserver représente chaque changement DOM en termes de sous-arbres. Donc, si vous attendez, par exemple, qu'un certain élément soit inséré, il peut être au plus profond des enfants de
mutations.mutation[i].addedNodes[j]
.Un autre problème est lorsque votre propre code, en réaction aux mutations, change de DOM - vous voulez souvent le filtrer.
Une bonne bibliothèque pratique qui résout ces problèmes est
mutation-summary
(avertissement: je ne suis pas l'auteur, juste un utilisateur satisfait), qui vous permet de spécifier des requêtes de ce qui vous intéresse et d'obtenir exactement cela.Exemple d'utilisation de base des documents:
la source