web-dev-qa-db-fra.com

La méthode la plus efficace pour détecter/surveiller les modifications du DOM?

J'ai besoin d'un mécanisme efficace pour détecter les modifications apportées au DOM. De préférence, plusieurs navigateurs, mais s’il existe un moyen efficace d'utiliser pas plusieurs navigateurs, je peux les implémenter avec une méthode de navigation croisée sans faille.

En particulier, je dois détecter les modifications susceptibles d’affecter le texte d’une page. Par conséquent, tout élément nouveau, supprimé ou modifié, ou toute modification du texte interne (innerHTML) est nécessaire.

Je n'ai pas de contrôle sur les modifications apportées (elles peuvent être dues à des scripts javascript tiers, etc.), de sorte que vous ne pouvez pas vous en approcher sous cet angle. J'ai besoin de "surveiller" les modifications d'une manière ou d'une autre.

Actuellement, j'ai implémenté une méthode "quick'n'dirty" qui vérifie body.innerHTML.length à intervalles réguliers. Bien entendu, cela ne détectera pas les modifications qui aboutiront au retour de la même longueur, mais dans ce cas, c'est "assez bon" - les chances que cela se produise sont extrêmement minces, et dans ce projet, l'absence de détection d'une modification ne résultera pas. en données perdues.

Le problème avec body.innerHTML.length est que cela coûte cher. Cela peut prendre entre 1 et 5 millisecondes avec un navigateur fast, ce qui peut gâcher beaucoup de choses - je suis également confronté à un nombre important d'iframes et tout s'additionne. Je suis persuadé que le coût de cette opération est coûteux, car le texte innerHTML n'est pas stocké de manière statique par les navigateurs et doit être calculé à partir du DOM à chaque lecture.

Les types de réponses que je recherche vont du "précis" (par exemple, l'événement) au "assez bon" - peut-être quelque chose d'aussi "rapide" que la méthode innerHTML.length, mais cela s'exécute plus rapidement.

EDIT: .__ Je devrais également signaler que s'il serait "agréable" de détecter l'élément précis qui a été modifié, ce n'est pas une nécessité absolue - le simple fait qu'il y ait eu tout changement serait assez bien. Espérons que cela élargisse les réponses des gens. Je vais étudier les événements de mutation, mais j'ai toujours besoin d'une solution de secours pour bénéficier du soutien de IE. Par conséquent, toute idée sournoise, créative et hors du commun serait la bienvenue.

42
Graza

http://www.quirksmode.org/js/events/DOMtree.html

jQuery supporte maintenant un moyen d'attacher des événements aux éléments existants et futurs correspondant à un sélecteur: http://docs.jquery.com/Events/live#typefn

Une autre découverte intéressante - http://james.padolsey.com/javascript/monitoring-dom-properties/

10
jagamot

Pour mettre cela à jour, le standard DOM4 supprime les événements de mutation et les remplace par des observateurs de mutation: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

30
zeveck

Mutation events sont les recommandations W3 de ce que vous recherchez.

Je ne sais pas s'ils sont supportés partout .. (IE ne les supportera probablement pas ..)

8
Gabriele Petrioli

Vous pouvez essayer d'utiliser les événements DOMNodeInserted et DOMNodeRemoved. Selon Quirksmode, ils fonctionnent plus ou moins dans la plupart des navigateurs, à l'exception notable de IE ... 

http://www.quirksmode.org/dom/events/index.html

1
Chibu

J'ai récemment écrit un plugin qui fait exactement cela - jquery.initialize

Vous l'utilisez de la même manière que la fonction .each

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

La différence par rapport à .each est la suivante: il faut votre sélecteur, dans ce cas .some-element et attendre que de nouveaux éléments avec ce sélecteur soient utilisés à l'avenir, si cet élément est ajouté, il sera également initialisé.

Dans notre cas, la fonction d'initialisation change simplement la couleur de l'élément en bleu. Donc, si nous ajoutons un nouvel élément (peu importe que ce soit avec ajax ou même un inspecteur F12 ou quoi que ce soit) comme:

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

Le plugin l'initialisera instantanément. Aussi, le plugin s'assure qu'un élément n'est initialisé qu'une fois. Donc, si vous ajoutez un élément, puis .deatch() le à partir du corps, puis ajoutez-le à nouveau, il ne sera pas initialisé à nouveau.

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

Le plugin est basé sur MutationObserver - il fonctionnera sous IE9 et 10 avec les dépendances détaillées dans la page readme .

1
pie6k

jQuery Mutate fait cela aussi, par défaut, il supporte comme height, width, scrollHeight etc ... mais il peut aussi être étendu avec un peu de code supplémentaire pour ajouter de nouveaux événements comme voir si le texte a changé, etc. . 

http://www.jqui.net/jquery-projects/jquery-mutate-official/

J'espère que ça aide 

0
Val