2012-02-28 21 views
17

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

Mi problema específico: Tengo una función 'información sobre herramientas' que muestra el contenido del atributo title de una manera elegante cuando haces un hover en cualquier elemento html. Sin embargo, al hacer un vuelo estacionario, el navegador muestra el title en su propio cuadro. Me gustaría suprimir eso. Entonces, lo que he pensado es mover los contenidos del atributo title a un atributo personalizado (HTML5) data-title la primera vez que se carga la página, y entonces mi función 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 'volver a vincular' esos elementos - cambie esos atributos de título nuevamente. Sería bueno si hubiera un oyente de eventos que escuchara esos cambios y reenlace los elementos automáticamente.

+0

posible duplicado de [Cómo identificar cuando el DOM se ha cambiado?] (Http://stackoverflow.com/questions/3744706/how-to-identify-when-the -dom-has-been-changed) –

+2

parece tratar de escuchar cada cambio en DOM ... y buscar sus elementos cada vez sería realmente costoso. – charlietfl

+0

posible duplicado de [¿Hay un escucha de cambio de jQuery DOM?] (Http://stackoverflow.com/questions/2844565/is-there-a-jquery-dom-change-listener) – APerson

Respuesta

33

Mi mejor conjetura es que usted quiere escuchar a los eventos de mutación DOM. Puede hacerlo mediante un evento de mutación DOM como cualquier evento javascript normal, como un clic del mouse.

se refieren a esto: W3 MutationEvent

Ejemplo:

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

No necesita las comillas en el controlador, es una forma de hacer que la función se vincule al evento. – MacMac

+1

este código puede parecer corto y dulce, pero la carga que pone en el navegador es más que insuficiente para este caso de uso cuando existen soluciones de delegación de eventos a continuación – charlietfl

+0

Mi error ... Agregué citas con prisa – nightf0x

2

[editado en respuesta a la investigación por el miembro de Tony]

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

En cuanto al n. ° 1: cuando enlaza su evento personalizado al elemento, puede usar event.preventDefault() para que no aparezcan los consejos sobre herramientas. Esto no funciona correctamente. Entonces, la solución para seguir utilizando el atributo "título" es tomar el valor, insertarlo en el objeto de datos (la función $.data()) y luego anular el título con una cadena vacía (removeAttr es inconsistente). Luego, en mouseleave, tomas el valor del objeto de datos y lo vuelves a insertar en el título. Esta idea proviene de aquí: How to disable tooltip in the browser with jQuery?

En relación con el n. ° 2: en lugar de volver a vincular el cambio DOM, solo tiene que vincular una vez a un elemento detector que nunca se espera que se destruya. Por lo general, este es un elemento contenedor de algún tipo, pero incluso puede ser document (aproximadamente .live(), que ahora está en desuso) si realmente necesita un contenedor que lo abarque todo. He aquí un ejemplo que utiliza algunas marcas falsa 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 storedTitle = $.data(this, 'title'); 
    $this.attr('title', storedTitle); 
}); 

Mi marcado realista (sólo 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 alguna controles de cordura: http://jsfiddle.net/GVDqn/1/

Probablemente haya una forma más óptima de hacerlo (sinceramente, no investigué si podría vincular dos funciones separadas para dos eventos separados con un selector), pero lo hará.

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

+0

enfoque más sensato aquí! .... luego dentro del mouseenter puede comprobar si el título se ha movido a $ (esto) .data ('título') o no – charlietfl

+0

habría sido la solución más elegante, pero parece que 'preventDefault' NO impide mostrar títulos en' mouseover' (al menos en Chrome) - http://code.google.com/p/chromium/issues/detail?id=42549 –

+0

@Tony Good find; Creo que también falló en Fx. He actualizado con un nuevo código. –

0

Según lo observado por Greg Pettit, debe utilizar la función on() en el elemento.

Lo que hace esto es que le permite enlazar un selector a un evento, luego jQuery agregará este controlador de eventos cuando los objetos devueltos por el selector estén disponibles.

Si quería una función para disparar en un ratón por encima del evento y que lo quería para disparar sobre todos los elementos con la clase de * FIELD_TITLE * que podría hacer esto:

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

Esto activará el el evento sobre el mouse sobre cualquier objeto que tenga la clase * field_title * y ejecute la función doSomething().

esperanza que tiene sentido :)

+1

Tiene un error tipográfico, debe ser '.bind ('mouseenter')' not '. ('mouseenter')'. – MacMac

Cuestiones relacionadas