Tengo un campo de entrada que abre un menú desplegable personalizado. Me gustaría la siguiente funcionalidad:
- Cuando el usuario hace clic en cualquier lugar fuera del campo de entrada, el menú debe eliminarse.
- Si, más específicamente, el usuario hace clic en un div dentro del menú, el menú debe eliminarse y debe producirse un procesamiento especial en función de qué div se hizo clic.
Aquí está mi implementación:
El campo de entrada tiene un onblur()
evento que elimina el menú (estableciendo su padre innerHTML
en una cadena vacía) cada vez que el usuario hace clic fuera del campo de entrada. Los divs dentro del menú también tienen onclick()
eventos que ejecutan el procesamiento especial.
El problema es que los onclick()
eventos nunca se activan cuando se hace clic en el menú, porque el campo de entrada se onblur()
activa primero y elimina el menú, incluidos los onclick()
s!
Resolví el problema dividiendo los divs del menú onclick()
en onmousedown()
y onmouseup()
eventos y estableciendo una bandera global al presionar el mouse hacia abajo que se borra al presionar el mouse hacia arriba, similar a lo que se sugirió en esta respuesta . Debido a que se onmousedown()
dispara antes onblur()
, la bandera se activará onblur()
si se hizo clic en uno de los divs del menú, pero no si se hizo en otro lugar de la pantalla. Si se hizo clic en el menú, vuelvo inmediatamente onblur()
sin eliminar el menú, luego espero a onclick()
que se active, momento en el que puedo eliminar el menú de forma segura.
¿Existe una solución más elegante?
El código se parece a esto:
<div class="menu" onmousedown="setFlag()" onmouseup="doProcessing()">...</div>
<input id="input" onblur="removeMenu()" ... />
var mouseflag;
function setFlag() {
mouseflag = true;
}
function removeMenu() {
if (!mouseflag) {
document.getElementById('menu').innerHTML = '';
}
}
function doProcessing(id, name) {
mouseflag = false;
...
}
fuente
onmousedown
se ejecutó antes.onblur
Probado en Firefox, Chrome e Internet Explorer.onMouseDown
conevent.preventDefault()
yonClick
con la acción deseada.onClick
no debe ser reemplazado cononMouseDown
.Si bien este enfoque funciona de alguna manera , los dos son eventos fundamentalmente diferentes que tienen expectativas diferentes a los ojos del usuario. Usando en
onMouseDown
lugar deonClick
arruinará la previsibilidad de su software en este caso. Por tanto, los dos eventos no son intercambiables.Para ilustrar: al hacer clic accidentalmente en un botón, los usuarios esperan poder mantener presionado el clic del mouse, arrastrar el cursor fuera del elemento y soltar el botón del mouse, lo que finalmente no produce ninguna acción.
onClick
Haz esto.onMouseDown
no permite que el usuario mantenga presionado el mouse y, en su lugar, activará inmediatamente una acción, sin ningún recurso para el usuario.onClick
es el estándar por el cual esperamos activar acciones en una computadora.En esta situación, llame
event.preventDefault()
alonMouseDown
evento.onMouseDown
causará un evento de desenfoque de forma predeterminada y no lo hará cuandopreventDefault
se llame. Entonces,onClick
tendrá la oportunidad de ser llamado. Un evento borroso seguirá ocurriendo, solo despuésonClick
.Después de todo, el
onClick
evento es una combinación deonMouseDown
yonMouseUp
, si y solo si ambos ocurren dentro del mismo elemento.fuente
event.preventDefault()
en unonMouseDown
evento, mionFocus
evento no se llamaReemplazar
onmousedown
cononfocus
. Entonces, este evento se activará cuando el foco esté dentro del cuadro de texto.Reemplazar
onmouseup
cononblur
. En el momento en que saque su enfoque del cuadro de texto, se ejecutará onblur.Supongo que esto es lo que podrías necesitar.
ACTUALIZAR :
cuando ejecute su función onfocus -> elimine las clases que aplicará en onblur y agregue las clases que desea que se ejecuten onfocus
y
cuando ejecuta su función onblur -> elimine las clases que aplicará en onfocus y agregue las clases que desea que se ejecuten onblur
No veo ninguna necesidad de variables de marca.
ACTUALIZACIÓN 2:
Puede utilizar los eventos onmouseout y onmouseover
el ratón por encima -Detecta cuando el cursor está sobre él.
onmouseout -Detecta cuando el cursor sale.
fuente
onmousedown()
yonmouseup()
en el menú, no el cuadro de texto / campo de entrada.Una solución más elegante (pero probablemente menos eficaz):
En lugar de usar el onblur de la entrada para eliminar el menú, use
document.onclick
, que se dispara despuésonblur
.Sin embargo, esto también significa que el menú se elimina cuando se hace clic en la entrada, lo que es un comportamiento no deseado. Establezca un
input.onclick
conevent.stopPropagation()
para evitar la propagación de clics al evento de clic del documento.fuente
cambiar onclick por onfocus
incluso si onblur y onclick no se llevan muy bien, pero obviamente onfocus y sí onblur. ya que incluso después de cerrar el menú, el enfoque sigue siendo válido para el elemento en el que se hace clic dentro.
Lo hice y funcionó.
fuente
Puede usar una
setInterval
función dentro de suonBlur
controlador, como esta:la
setInterval
función eliminará suonBlur
función de la pila de llamadas, agregue porque estableció el tiempo en 0, esta función se llamará inmediatamente después de que finalice otro controlador de eventosfuente
setInterval
es una mala idea, nunca la cancelará, por lo que ejecutará continuamente su función y lo más probable es que haga que su sitio use max cpu. ÚselosetTimeout
en su lugar si va a usar esta técnica (que no recomiendo). Hacer que su aplicación dependa de la sincronización de ciertos eventos es un negocio arriesgado.setTimeout
nosetInterval
) pero tuve que aumentarla a250
ms antes de que ocurriera el tiempo en el orden correcto. Este error probablemente seguirá existiendo en dispositivos más lentos y también hace que el retraso sea notable. ProbéonMouseDown
y funciona bien. Me pregunto si también necesita los eventos táctiles.