jQuery: ¿Cómo escuchar los cambios DOM?

¿Es posible y cómo puedo escuchar los cambios a través de todo el tree DOM con jQuery?

Mi problema específico: tengo una function 'información sobre herramientas' que muestra el contenido del atributo de title de una manera elegante cuando haces un hover del hover sobre cualquier elemento html. Sin embargo, al hacer un vuelo estacionario, el browser muestra el title en su propio cuadro. Me gustaría suprimir eso. Entonces, lo que he pensado es mover el contenido del atributo de title a un atributo de title data-title personalizado (HTML5) la primera vez que se carga la página, y entonces la function de información sobre herramientas funcionará con data-title .

El problema es que más adelante podría agregar / eliminar / cambiar el HTML dinámicamente, así que tengo que 'reenlazar' esos elementos – cambie esos attributes de título nuevamente. Sería bueno si hubiera un oyente de events que escuchara esos cambios y reenlace los elementos automáticamente.

Mi mejor suposition es que quieres escuchar los events de mutación DOM. Puede hacerlo mediante un evento de mutación DOM como cualquier evento javascript normal, como un clic del mouse.

Consulte esto: W3 MutationEvent

Ejemplo:

 $("element-root").bind("DOMSubtreeModified", "CustomHandler"); 

[editado en respuesta a la investigación del miembro Tony]

Entonces, sin código adicional, esto es un poco a ciegas, pero me parece que hay dos cosas en las que pensar: 1. el comportamiento pnetworkingeterminado de la información sobre herramientas del browser; 2. un DOM potencialmente actualizado y la posibilidad de que sus tooltips personalizados continúen funcionando.

Respecto al # 1: cuando vincula su evento personalizado al elemento, puede usar event.preventDefault() para que no aparezca la información sobre herramientas. Esto no funciona correctamente Entonces, la solución para seguir usando el atributo "título" es tomar el valor, insertlo en el object de datos (la function $.data() ) y luego anular el título con una cadena vacía (removeAttr es inconsistente). Luego, en mouseleave, tomas el valor del object de datos y lo vuelves a insert en el título. Esta idea proviene de aquí: ¿Cómo desactivar la información sobre herramientas en el browser con jQuery?

Con respecto al n. ° 2: en lugar de volver a vincular el cambio de DOM, solo necesita vincular una vez a un elemento de escucha que nunca se espera que se destruya. Por lo general, este es un elemento contenedor de algún tipo, pero incluso puede ser un document (aproximándose .live() que ahora está en desuso) si realmente necesita un contenedor que lo abarque todo. Aquí hay una muestra que usa un marcado falso de mi propia invención:

 var container = $('.section'); container.on('mouseenter', 'a', function() { var $this = $(this); var theTitle = $this.attr('title'); $this.attr('title', ''); $('#notatooltip').html(theTitle); $.data(this, 'title', theTitle); }); container.on('mouseleave', 'a', function() { $('#notatooltip').html(''); var $this = $(this); var stonetworkingTitle = $.data(this, 'title'); $this.attr('title', stonetworkingTitle); }); 

Mi marcado irreal (solo para este ejemplo) está aquí:

 <div class="section"> <a href="#" title="foo">Hover this foo!</a> <div id="notatooltip"></div> </div> 

Y un violín está aquí: http://jsfiddle.net/GVDqn/ O con algunos controles de cordura: http://jsfiddle.net/GVDqn/1/

Probablemente exista una forma más óptima de hacerlo (honestamente, no investigué si podrías vincular dos funciones separadas para dos events separados con un selector) pero funcionará.

No debería necesitar volver a vincular en function del cambio DOM, el oyente delegado lo manejará automáticamente. Y debería poder evitar la funcionalidad pnetworkingeterminada de información sobre herramientas simplemente impidiéndola.

Como notó Greg Pettit, deberías estar usando la function on () en el elemento.

Lo que hace esto es que le permite vincular un selector a un evento, luego jQuery agregará este controller de events cuando los objects devueltos por el selector estén disponibles.

Si quería que una function se activara con un mouse sobre el evento y deseaba disparar sobre todos los elementos con la class * field_title * , haría esto:

 $('.field_title').bind('mouseenter', function() { doSomething(); }); 

Esto se desencadenará en el evento over over mouse en cualquier object que tenga la class de * field_title * y ejecute la function doSomething () .

Espero que tenga sentido 🙂