2012-08-23 16 views
8

Tengo un div en una página que muestra información sobre una categoría en particular (Imagen, Nombre, etc.).Evitar disparar el evento desenfoque si alguno de sus hijos recibe foco

Cuando hago clic en la imagen de edición, coloca la categoría en modo de edición, lo que me permite actualizar el nombre. Como puede ver en la imagen a continuación, muestra que "Soup" se encuentra actualmente en modo de edición, los otros están en modo de vista normal. Todo esto funciona como se espera con los botones cancelar/guardar haciendo todo bien. (Traté de agregar una imagen pero no me dejó, necesito más amor)

Sin embargo, una vez en el modo de edición si hago clic en cualquier otro lugar de la página (Fuera del div) el resultado esperado sería que la sopa la categoría volvería al modo de visualización. Después de un evento de disparo de algún tipo, esto también debería permitirme preguntar si querían guardar los cambios.

Entonces, lo que decidí hacer fue crear un evento de desenfoque en el div principal de "sopas". Esto funciona como se esperaba si hago clic en cualquier parte de la página, sin embargo, si hago clic en el elemento interno de div, también provoca que se desencadene el desenfoque de los padres, lo que provoca que la categoría regrese al modo de visualización.

Entonces, ¿hay alguna forma de evitar que el div principal active el desenfoque si alguno de sus hijos recibe el foco?

<div tabindex="-1" onblur="alert('outer')"> 
    <input type="text" value="Soup" /> 
</div> 

acabo de escribieron el código sin un compilador así que no sé si es que aun funciona pero con que se espera que usted consigue la idea.

Estoy usando Knockout.js para actualizar la GUI sobre la marcha, pero eso no debería afectar esta respuesta, no lo hubiera pensado.

+0

[Pregunta relacionada] (http://stackoverflow.com/questions/121499/when-onblur-occurs-how-can-i-find -out-which-element-focus-went-to) – jbabey

Respuesta

21

He tenido que abordar este problema antes. No estoy seguro de si es la mejor solución, pero es lo que terminé usando.

Dado que el evento de clic se dispara después del desenfoque, no hay una forma (cruzada, confiable) de decir qué elemento está enfocando.

Mousedown, sin embargo, se dispara antes del desenfoque. Esto significa que puede establecer un indicador en el mousedown de los elementos secundarios e interrogar ese indicador en la imagen borrosa de su elemento primario.

Ejemplo de trabajo: http://jsfiddle.net/L5Cts/

en cuenta que también tendrá que manejar keydown (y comprobar si hay pestaña/shift-tab) si quieres también captura desdibuja causada por el teclado.

+2

Señor, usted es un caballero y un erudito.He estado probando diferentes soluciones a este problema en diferentes situaciones durante más de un año. Nunca me di cuenta del momento de todos los eventos, gracias un millón. –

+0

He estado tratando de encontrar algún tipo de definición oficial de orden/precedencia de eventos para ver si se puede confiar en esto. Esta es una vieja pregunta, pero si la respuesta sigue siendo cierta, esta solución podría funcionar solo por coincidencia: https://stackoverflow.com/a/282271/2382483. Me encantaría encontrar una solución realmente sólida para esto, pero todo parece funcionar o piratear. –

0

No creo que haya ninguna garantía de que mousedown suceda antes de los eventos de enfoque en todos los navegadores, así que una mejor manera de manejar esto podría ser usar evt.relatedTarget. Para el evento focusin, la propiedad eventTarget es una referencia al elemento que actualmente está perdiendo el foco. Puedes verificar si ese elemento es un descendiente del padre, y si no lo es, sabes que el foco está ingresando al padre desde el exterior. Para el evento focusout, relatedTarget es una referencia al elemento que actualmente es recibiendo focus. Utilizar la misma lógica para determinar si el foco está dejando totalmente al padre:

const parent = document.getElementById('parent'); 

parent.addEventListener('focusin', e => { 
    const enteringParent = !parent.contains(e.relatedTarget); 

    if (enteringParent) { 
     // do things in response to focus on any child of the parent or the parent itself 
    } 
}); 

parent.addEventListener('focusout', e => { 
    const leavingParent = !parent.contains(e.relatedTarget); 

    if (leavingParent) { 
     // do things in response to fully leaving the parent element and all of its children 
    } 
}); 
Cuestiones relacionadas