uso observer observe mutationobserver lugar eventos event está desaprobado changes change javascript jquery dom event-handling mutation-observers

javascript - observer - Evento cuando elemento agregado a la página



mutationobserver jquery (7)

Esto fue discutido previamente aquí: ¿Cómo hacer una acción cuando un elemento se agrega a una página usando Jquery?

El respondedor sugirió activar un evento personalizado siempre que se agregara un div a la página. Sin embargo, estoy escribiendo una extensión de Chrome y no tengo acceso al origen de la página. ¿Cuáles son mis opciones aquí? Supongo que en teoría podría usar setTimeout para buscar continuamente la presencia del elemento y agregar mi acción si el elemento está allí.


Como los eventos de mutación DOM ahora están en deprecated (vea la nota en la parte inferior) con las últimas especificaciones, y usted no tiene control sobre los elementos insertados porque el código de otra persona los agrega, su única opción es verificarlos continuamente.

function checkDOMChange() { // check for any new element being inserted here, // or a particular node being modified // call the function again after 100 milliseconds setTimeout( checkDOMChange, 100 ); }

Una vez que se llame a esta función, se ejecutará cada xxx milisegundos. Elegí 100, que es 1/10 (una décima) de segundo. A menos que necesite capturar elementos en tiempo real, debería ser suficiente.

Editar

Como comentó Ben Davis, la especificación DOM Nivel 4 introduce observadores de mutaciones (también en documentos de Mozilla ), que reemplazan los eventos de mutación en desuso.


Hay una prometedora biblioteca de JavaScript llamada Arrive que parece una excelente manera de empezar a aprovechar los observadores de la mutación una vez que el soporte del navegador se convierte en algo común.

https://github.com/uzairfarooq/arrive/



Mira este plugin que hace exactamente eso - jquery.initialize

Funciona exactamente como cada función, la diferencia es que toma el selector que ha ingresado y está atento a los nuevos elementos agregados en el futuro que coinciden con este selector y los inicializa

Initialize se ve así

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

Pero ahora, si en la página aparece un nuevo selector de .some-element , se inicializará al instante.

La forma en que se agrega el nuevo elemento no es importante, no necesita preocuparse por las devoluciones de llamada, etc.

Entonces, si agregas un nuevo elemento como:

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

se inicializará instantáneamente.

El complemento está basado en MutationObserver


Puede usar el complemento livequery para jQuery. Puede proporcionar una expresión de selector como, por ejemplo:

$("input[type=button].removeItemButton").livequery(function () { $("#statusBar").text(''You may now remove items.''); });

Cada vez que se agrega un botón de una clase removeItemButton , aparece un mensaje en una barra de estado.

En términos de eficiencia, es posible que desee evitar esto, pero en cualquier caso podría aprovechar el complemento en lugar de crear sus propios controladores de eventos.

Respuesta revisada

La respuesta anterior solo pretendía detectar que un elemento se haya agregado al DOM a través del complemento.

Sin embargo, lo más probable es que un enfoque jQuery.on() sea ​​más apropiado, por ejemplo:

$("#myParentContainer").on(''click'', ''.removeItemButton'', function(){ alert($(this).text() + '' has been removed''); }

Si tiene contenido dinámico que debe responder a los clics, por ejemplo, es mejor vincular los eventos a un contenedor principal utilizando jQuery.on .



ETA 24 de abril 17 Quería simplificar esto un poco con algo de magia async / await , ya que lo hace mucho más sucinto:

Usando el mismo promisificado-observable:

const startObservable = (domNode) => { var targetNode = domNode; var observerConfig = { attributes: true, childList: true, characterData: true }; return new Promise((resolve) => { var observer = new MutationObserver(function (mutations) { // For the sake of...observation...let''s output the mutation to console to see how this all works mutations.forEach(function (mutation) { console.log(mutation.type); }); resolve(mutations) }); observer.observe(targetNode, observerConfig); }) }

Su función de llamada puede ser tan simple como:

const waitForMutation = async () => { const button = document.querySelector(''.some-button'') if (button !== null) button.click() try { const results = await startObservable(someDomNode) return results } catch (err) { console.error(err) } }

Si desea agregar un tiempo de espera, puede usar un patrón Promise.race simple como se muestra aquí :

const waitForMutation = async (timeout = 5000 /*in ms*/) => { const button = document.querySelector(''.some-button'') if (button !== null) button.click() try { const results = await Promise.race([ startObservable(someDomNode), // this will throw after the timeout, skipping // the return & going to the catch block new Promise((resolve, reject) => setTimeout( reject, timeout, new Error(''timed out waiting for mutation'') ) ]) return results } catch (err) { console.error(err) } }

Original

Puedes hacer esto sin bibliotecas, pero tendrías que usar algo de ES6, así que ten en cuenta los problemas de compatibilidad (es decir, si tu audiencia es mayoritariamente Amish, luddite o, lo que es peor, usuarios de IE8)

Primero, usaremos la API MutationObserver para construir un objeto observador. Vamos a envolver este objeto en una promesa, y resolve() cuando se active la devolución de llamada (h / t davidwalshblog) artículo del blog de david walsh sobre mutaciones :

const startObservable = (domNode) => { var targetNode = domNode; var observerConfig = { attributes: true, childList: true, characterData: true }; return new Promise((resolve) => { var observer = new MutationObserver(function (mutations) { // For the sake of...observation...let''s output the mutation to console to see how this all works mutations.forEach(function (mutation) { console.log(mutation.type); }); resolve(mutations) }); observer.observe(targetNode, observerConfig); }) }

Entonces, crearemos una generator function . Si aún no los ha usado, entonces se está perdiendo, pero una breve sinopsis es: se ejecuta como una función de sincronización, y cuando encuentra una expresión de yield <Promise> , espera de forma no bloqueante para la promesa de cumplirse (los generadores hacen más que esto, pero esto es lo que nos interesa aquí ).

// we''ll declare our DOM node here, too let targ = document.querySelector(''#domNodeToWatch'') function* getMutation() { console.log("Starting") var mutations = yield startObservable(targ) console.log("done") }

Una parte difícil de los generadores es que no "regresan" como una función normal. Entonces, usaremos una función auxiliar para poder usar el generador como una función normal. (de nuevo, h / t a dwb )

function runGenerator(g) { var it = g(), ret; // asynchronously iterate over generator (function iterate(val){ ret = it.next( val ); if (!ret.done) { // poor man''s "is it a promise?" test if ("then" in ret.value) { // wait on the promise ret.value.then( iterate ); } // immediate value: just send right back in else { // avoid synchronous recursion setTimeout( function(){ iterate( ret.value ); }, 0 ); } } })(); }

Luego, en cualquier momento antes de que ocurra la mutación DOM esperada, simplemente ejecute runGenerator(getMutation) .

Ahora puede integrar mutaciones DOM en un flujo de control de estilo síncrono. ¿Qué tal eso?