2010-03-16 24 views
41

Necesito un mecanismo eficiente para detectar cambios en el DOM. Preferiblemente navegador cruzado, pero si hay medios eficientes que son no navegador cruzado, puedo implementar estos con un método de navegador cruzado a prueba de fallas.¿El método más eficiente para detectar/monitorear cambios DOM?

En particular, necesito detectar los cambios que afectarían el texto en una página, por lo que cualquier elemento nuevo, eliminado o modificado, o cambios en el texto interno (innerHTML) serían necesarios.

No tengo control sobre los cambios que se están realizando (pueden deberse a Javascript incluido por terceros, etc.), por lo que no se puede abordar desde este ángulo. De alguna manera, necesito "monitorear" los cambios.

Actualmente he implementado un método "quick'n'dirty" que comprueba body.innerHTML.length a intervalos. Esto, por supuesto, no detectará cambios que den como resultado que se devuelva la misma longitud, pero en este caso es "suficientemente bueno": las posibilidades de que esto ocurra son extremadamente escasas, y en este proyecto, no detectar un cambio no resultará en datos perdidos El problema con body.innerHTML.length es que es costoso. Puede tomar entre 1 y 5 milisegundos en un rápido navegador, y esto puede atascar mucho las cosas - También estoy lidiando con un gran número de iframes y todo suma. Estoy bastante seguro de que el costo de hacerlo es porque el texto innerHTML no está almacenado estáticamente por los navegadores, y debe calcularse desde el DOM cada vez que se lee.

Los tipos de respuestas que estoy buscando son cualquier cosa, desde el "preciso" (por ejemplo, el evento) al "suficientemente bueno" - tal vez algo tan "rápido" como el método innerHTML.length, pero que se ejecuta más rápido.

EDIT: También cabe señalar que, si bien sería "agradable" para detectar el elemento precisa que ha sido modificado, no es una necesidad absoluta - sólo el hecho de que ha habido cualquier cambio sería suficientemente bueno. Con suerte, esto amplía las respuestas de las personas. Voy a investigar los eventos de mutación, pero todavía necesito un respaldo para el soporte de IE, por lo que cualquier idea extravagante, creativa y fuera de la plaza sería muy bienvenida.

+0

No tuve mucha suerte la última vez que se me preguntó esto: http://stackoverflow.com/questions/648996/how-do-i-monitor-the-dom-for-changes –

+0

Sí, lo vi y estás correcto ... no mucha suerte. * Sin embargo *, porque no necesito el 100% de precisión, y también porque no necesito identificar qué elemento ha cambiado, solo que * ha habido * un cambio, espero que las personas presenten algunas soluciones creativas para mí ... – Graza

+0

Posible duplicado de [¿Hay un detector de cambios DOM de JavaScript/jQuery?] (https://stackoverflow.com/questions/2844565/is-there-a-javascript-jquery-dom-change-listener) – Makyen

Respuesta

9

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

jQuery ahora soporta una manera de unir a los acontecimientos actuales y futuros elementos correspondientes a un selector: http://docs.jquery.com/Events/live#typefn

Otro hallazgo interesante - http://james.padolsey.com/javascript/monitoring-dom-properties/

+0

Gracias, parece que cubre todas las bases: eventos DOMTree para no IE y 'onPropertyChange' para IE. Todavía no he implementado el evento 'onPropertyChange', pero lo haré; vea mis comentarios en la publicación de @ Gaby para obtener una actualización de lo que se ha hecho hasta ahora. – Graza

+0

El método 'live()' de jQuery no parece funcionar mejor en IE, así que también estoy usando un 'bind()' estándar (luego 'unbind(). Bind()' en cualquier cambio en caso de que algo nuevo ha sido agregado), pero el uso de los eventos DOMTree, junto con 'onPropertyChange', y un setInterval fallback, parece ser el truco. 'watch()' parecía demasiada molestia (tendría que agregar manualmente a todos los elementos ya que no es un tipo de evento estándar, es solo un método), y no estoy seguro de que sea compatible en varios navegadores, mientras que el otro dos métodos parecían cubrir la mayoría de las bases. – Graza

+2

FYI: "A partir de jQuery 1.7, el método .live() está en desuso. Use .on() para adjuntar controladores de eventos.Los usuarios de versiones anteriores de jQuery deben usar .delegate() en preferencia a .live(). "[De documentos] (http://api.jquery.com/live/#typefn) –

7

Mutation events son la recomendación W3 de lo que busca ..

No estoy seguro si son compatibles en todo .. (IE lo más probable es que no apoyarlos ..)

+0

Ahora estoy usando estos eventos. Todavía estoy buscando 'body.innerHTML.length' en intervalos establecidos, pero si se desencadena alguno de estos eventos, asumo que la verificación periódica ya no es necesaria y la cambio. apagado. Todavía tengo que investigar 'onPropertyChange' y' watch() 'como alternativas, y probablemente implemente estos usando una idea similar, ya que si se activan, puedo cancelar cualquier otra comprobación:' onPropertyChange' podría funcionar en IE pero no otros navegadores – Graza

+0

Los eventos de mutación están actualmente en desuso en favor de Mutation Observers https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver –

1

Usted podría tratar de usar los eventos DOMNodeInserted y DOMNodeRemoved. Según Quirksmode, que tipo de trabajo en la mayoría de los navegadores, con la notable excepción del IE ...

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

+0

Son dos de los tipos de eventos de mutación, que se introdujeron en DOM nivel 2. Existen un puñado más de tipos de eventos. –

1

he escrito recientemente un plugin que hace exactamente eso - jquery.initialize

se usa la misma manera que .each función

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

La diferencia de .each es - que toma el selector, en este caso .some-element y esperar a que los nuevos elementos con este selector en el futuro, si se añade como elemento, éste se inicializará también.

En nuestro caso, la función de inicialización simplemente cambia el color del elemento a azul. Así que si vamos a añadir nuevo elemento (no importa si con el Ajax o incluso inspector de F12 o cualquier cosa) como:

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

Plugin init al instante. Además, el complemento se asegura de que un elemento se inicialice solo una vez. Entonces, si agrega un elemento, entonces .deatch() del cuerpo y luego lo vuelve a agregar, no se inicializará nuevamente.

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

Plugin se basa en MutationObserver - que funcionará en IE9 y 10 con dependencias como se detalla en el readme page.

Cuestiones relacionadas