¿Hay un detector de cambio de DOM de JavaScript / jQuery?
402
Esencialmente quiero que se ejecute un script cuando el contenido de un DIVcambio. Como las secuencias de comandos están separadas (secuencia de comandos de contenido en la extensión de Chrome y secuencia de comandos de la página web), necesito una forma de simplemente observar los cambios en el estado DOM. Podría establecer encuestas, pero eso parece descuidado.
Durante mucho tiempo, los eventos de mutación DOM3 fueron la mejor solución disponible, pero han quedado en desuso por razones de rendimiento. Los observadores de mutación DOM4 son el reemplazo de los eventos de mutación DOM3 en desuso. Están implementados actualmente en los navegadores modernos como MutationObserver(o como el proveedor prefijada WebKitMutationObserveren las versiones anteriores 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//...});
Este ejemplo escucha los cambios DOM documenty todo su subárbol, y disparará los cambios a los atributos del elemento, así como los cambios estructurales. El borrador de la especificación tiene una lista completa de propiedades de escucha de mutación válidas :
childList
Establezca truesi se deben observar mutaciones en los hijos del objetivo.
atributos
Establezca truesi se deben observar mutaciones en los atributos del objetivo.
characterData
Establezca truesi se van a observar mutaciones en los datos del objetivo.
subárbol
Establezca truesi las mutaciones no solo apuntan, sino también a los descendientes del objetivo.
attributeOldValue
Establecer en truesi attributesse establece en verdadero y el valor del atributo del objetivo antes de que la mutación deba registrarse.
characterDataOldValue
Establecer en truesi characterDatase establece en verdadero y los datos del objetivo antes de que la mutación deba registrarse.
attributeFilter
Establezca una lista de nombres locales de atributos (sin espacio de nombres) si no es necesario observar todas las mutaciones de atributos.
(Esta lista está actualizada a abril de 2014; puede consultar la especificación para ver si hay cambios).
@AshrafBashir Veo que la muestra funciona bien en Firefox 19.0.2: veo ([{}])registrada en la consola, que muestra lo esperado MutationRecordcuando hago clic en ella. Vuelva a verificar, ya que podría haber sido una falla técnica temporal en JSFiddle. Todavía no lo he probado en IE, ya que no tengo IE 10, que actualmente es la única versión que admite eventos de mutación.
apsillers
1
Acabo de publicar una respuesta que funciona en IE10 + y sobre todo en cualquier otra cosa.
naugtur
1
La especificación ya no parece tener un cuadro verde que enumere las opciones del observador de mutaciones. Lo hace la lista de las opciones en la sección 5.3.1 y los describe sólo un poco más debajo de eso.
LS
2
@LS Gracias, actualicé el enlace, eliminé el bit sobre el cuadro verde y edité la lista completa en mi respuesta (en caso de que el enlace se pudra en el futuro).
Esta respuesta ahora está en desuso. Ver la respuesta de apsillers .
Dado que esto es para una extensión de Chrome, también puede usar el evento DOM estándar DOMSubtreeModified. Consulte el soporte para este evento en todos los navegadores. Ha sido compatible con Chrome desde 1.0.
Todavía funciona si estás creando extensiones de Chrome. inestimable.
concept47
49
Muchos sitios usan AJAX para agregar / mostrar / cambiar contenido dinámicamente. A veces se usa en lugar de la navegación en el sitio, por lo que la URL actual se cambia mediante programación y los scripts de contenido no se ejecutan automáticamente por el navegador en este caso, ya que la página no se obtiene del servidor remoto por completo.
Métodos habituales de JS para detectar cambios de página disponibles en un script de contenido .
MutationObserver ( docs ) para detectar literalmente los cambios DOM:
Comprobación periódica de DOM a través de setInterval :
Obviamente, esto funcionará solo en los casos en que espere a que aparezca un elemento específico identificado por su id / selector, y no le permitirá detectar universalmente nuevo contenido agregado dinámicamente a menos que invente algún tipo de huella digital Los contenidos existentes.
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();});
Otro enfoque dependiendo de cómo esté cambiando el div. Si está utilizando JQuery para cambiar el contenido de un div con su método html (), puede extender ese método y llamar a una función de registro cada vez que coloque html en 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 );
Simplemente interceptamos las llamadas a html (), llamamos a una función de registro con esto, que en el contexto se refiere al elemento objetivo que obtiene nuevo contenido, luego pasamos la llamada a la función jquery.html () original. Recuerde devolver los resultados del método html () original, porque JQuery lo espera para el encadenamiento de métodos.
Además de las herramientas "en bruto" proporcionadas por MutationObserverAPI , existen bibliotecas de "conveniencia" para trabajar con mutaciones DOM.
Considere: MutationObserver representa cada cambio de DOM en términos de subárboles. Entonces, si está esperando, por ejemplo, que se inserte un determinado elemento, puede estar profundamente dentro de los hijos demutations.mutation[i].addedNodes[j] .
Otro problema es cuando su propio código, en reacción a las mutaciones, cambia el DOM; a menudo desea filtrarlo.
Una buena biblioteca de conveniencia que resuelve tales problemas es mutation-summary (descargo de responsabilidad: no soy el autor, solo un usuario satisfecho), que le permite especificar consultas de lo que le interesa y obtener exactamente eso.
([{}])
registrada en la consola, que muestra lo esperadoMutationRecord
cuando hago clic en ella. Vuelva a verificar, ya que podría haber sido una falla técnica temporal en JSFiddle. Todavía no lo he probado en IE, ya que no tengo IE 10, que actualmente es la única versión que admite eventos de mutación.Editar
Esta respuesta ahora está en desuso. Ver la respuesta de apsillers .
Dado que esto es para una extensión de Chrome, también puede usar el evento DOM estándar
DOMSubtreeModified
. Consulte el soporte para este evento en todos los navegadores. Ha sido compatible con Chrome desde 1.0.Vea un ejemplo de trabajo aquí .
fuente
Muchos sitios usan AJAX para agregar / mostrar / cambiar contenido dinámicamente. A veces se usa en lugar de la navegación en el sitio, por lo que la URL actual se cambia mediante programación y los scripts de contenido no se ejecutan automáticamente por el navegador en este caso, ya que la página no se obtiene del servidor remoto por completo.
Métodos habituales de JS para detectar cambios de página disponibles en un script de contenido .
MutationObserver ( docs ) para detectar literalmente los cambios DOM:
Detector de eventos para sitios que indican cambios en el contenido enviando un evento DOM:
pjax:end
Endocument
muchos sitios basados en pjax, por ejemplo, GitHub,consulte ¿Cómo ejecutar jQuery antes y después de una carga de pjax?
message
elwindow
utilizado por ejemplo de búsqueda de Google en el navegador Chrome,consulte extensión de Chrome detecta la búsqueda de Google de actualización
spfdone
endocument
Youtube,vea ¿Cómo detectar la navegación de la página en Youtube y modificar el HTML antes de que se renderice la página?
Comprobación periódica de DOM a través de setInterval :
Obviamente, esto funcionará solo en los casos en que espere a que aparezca un elemento específico identificado por su id / selector, y no le permitirá detectar universalmente nuevo contenido agregado dinámicamente a menos que invente algún tipo de huella digital Los contenidos existentes.
Historial de ocultación API dentro de un script DOM inyectado :
Escuchar eventos hashchange , popstate :
Extensiones específicas: detecta cambios de URL en una página de fondo / evento .
Existen API avanzadas para trabajar con la navegación: webNavigation , webRequest , pero usaremos un detector de eventos simple chrome.tabs.onUpdated que envía un mensaje al script de contenido:
manifest.json:
declarar página de fondo / evento
declarar contenido script
agregar
"tabs"
permiso .background.js
content.js
fuente
Otro enfoque dependiendo de cómo esté cambiando el div. Si está utilizando JQuery para cambiar el contenido de un div con su método html (), puede extender ese método y llamar a una función de registro cada vez que coloque html en un div.
Simplemente interceptamos las llamadas a html (), llamamos a una función de registro con esto, que en el contexto se refiere al elemento objetivo que obtiene nuevo contenido, luego pasamos la llamada a la función jquery.html () original. Recuerde devolver los resultados del método html () original, porque JQuery lo espera para el encadenamiento de métodos.
Para obtener más información sobre la anulación y extensión de métodos, consulte http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm , que es donde Puse la función de cierre. Consulte también el tutorial sobre complementos en el sitio de JQuery.
fuente
Además de las herramientas "en bruto" proporcionadas por
MutationObserver
API , existen bibliotecas de "conveniencia" para trabajar con mutaciones DOM.Considere: MutationObserver representa cada cambio de DOM en términos de subárboles. Entonces, si está esperando, por ejemplo, que se inserte un determinado elemento, puede estar profundamente dentro de los hijos de
mutations.mutation[i].addedNodes[j]
.Otro problema es cuando su propio código, en reacción a las mutaciones, cambia el DOM; a menudo desea filtrarlo.
Una buena biblioteca de conveniencia que resuelve tales problemas es
mutation-summary
(descargo de responsabilidad: no soy el autor, solo un usuario satisfecho), que le permite especificar consultas de lo que le interesa y obtener exactamente eso.Ejemplo de uso básico de los documentos:
fuente