2011-09-16 13 views
38

Necesito saber cuándo el cursor del mouse deja un div. Así que conecto el evento mouseout. Sin embargo, si muevo el mouse muy rápidamente fuera del div, el evento mouseoutno se activa. Eso es correcto: el cursor del mouse era sentado todavía dentro de div, ahora es fuera dediv, y sin embargo no se ha llamado al mouseout devolución de llamada. (Funciona bien si no muevo el mouse muy rápido.)¿Por qué no puedo capturar de manera confiable un evento de mouseout?

Esto es cierto en el más reciente Google Chrome por cierto, así que no es solo un problema de "navegadores antiguos".

Una solución:

Una pregunta acerca de este problema ha sido posed before. Aparentemente es solo un hecho de la vida, y la única solución que he encontrado es monitorear manualmente los eventos mousemove, cada vez que compruebo las coordenadas x/y del cursor y veo si están dentro del cuadro delimitador div, por lo que tienes más posibilidades de "notar" si el cursor ya no está dentro de él.

En comparación con dejar que el navegador haga todo esto de forma nativa, realizar cálculos en cada movimiento de píxel es un poco de un golpe de rendimiento. También es tedioso codificar.

a mi pregunta ...

¿Por qué no puede el navegador no puede capturar de forma fiable el evento mouseout? Si puedo decir de manera confiable cuándo el mouse dejó el div usando la solución anterior, ¿por qué el navegador no puede hacerlo?

Entiendo (de la respuesta vinculada anteriormente) que JavaScript no intenta interpolar "marcos". Supongamos que si coloca un controlador mousemove en el document y mueve rápidamente el mouse 200 píxeles hacia la derecha en una línea horizontal perfecta, puede no obtener 200 mousemove eventos. Algunos serán extrañados. No tengo un problema con eso.

Pero si se pierden algunos movimientos de píxel justo cuando el mouse cruza el límite del div, ¿por qué sigue que el evento mouseout también debe omitirse? Cuando el navegador fin empieza registrar la posición del ratón de nuevo (después de un rápido movimiento repentino), incluso si el ratón está ahora millas fuera de la caja, el punto es que solía ser en la caja y ya no lo es. Entonces, ¿por qué no dispara el evento mouseout entonces?

No entiendo por qué esto sería un problema difícil de resolver para los proveedores de navegadores. (Pero confío en que podría haber una buena razón, que soy demasiado estúpido para pensar.)

Estoy publicando esta pregunta principalmente por curiosidad, pero espero que la respuesta pueda dar una idea que podría ayúdame a solucionar el problema de manera más eficiente. Además, cualquier solución alternativa (que sea más rápida que la presentada anteriormente) sería bienvenida.

+1

Esto es de ninguna ayuda para usted (de aquí un comentario, en lugar de una respuesta), pero que el comportamiento más definitivamente suena como un error. Probablemente también sea obvio, pero para responder a su pregunta "¿por qué se sigue que el evento mouseout también se debe omitir?", La respuesta sería que * no *, ya que es un comportamiento no intencional. – jmar777

+0

Interesante. Eso es mucha ayuda para mí en realidad, si tienes razón, es un error. ¡Me parece extraño que este tipo de error exista en Chrome 15! Voy a hacer una página de prueba y probarla en otros navegadores para ver qué tan extendida está. Y podría enviar un informe de error a crbug.com y ver qué hacen con él. Gracias. – callum

+0

FYI: Chrome 15 no está en el canal estable aún – Candide

Respuesta

6

Sé que no quiere una solución alternativa, pero no necesita comprobar las x/y del mouse para saber si está dentro o fuera de un elemento. Simplemente puede verificar el elemento desde el cual se activó el evento mousemove.Si coloca un mousemove en el documento, el evento se disparará desde uno de sus elementos secundarios, y puede comparar ese elemento con su elemento para saber si es uno de sus descendientes.

O puede ir hasta el árbol parentNode y detenerse si encuentra su elemento. Entonces sabrá que está dentro del elemento y aún está dentro de él, de lo contrario, llegará al documento y saldrá.

Algunos navegadores implementan el mouseenter/mouseleave eventos que, he notado, son más precisos que mouseout. Prototype y jQuery tienen una solución alternativa para los navegadores que no implementan estos nuevos eventos. Mouseleave no se activa desde los elementos de un elemento, mientras que mouseout sí.

4

Describe el movimiento del mouse muy rápidamente. Cuando se detiene, ¿el puntero aún está dentro de la página? Es decir, ¿su puntero del mouse aún se encuentra sobre alguna parte de la página web visible?

Si ha salido, entonces no está necesariamente claro qué debe hacer el navegador. El evento mouseout debe tener una propiedad relatedTarget orientada a lo que ha pasado el puntero del mouse. Si el puntero del mouse ya está fuera del área de la página, no habría un objetivo relacionado al que apuntar.

Dicho de otra forma, cuando el mouse deja el área de la página, el navegador deja de rastrearlo y deja de informar su posición. Si mueves tu mouse lo suficientemente rápido, desde la perspectiva del navegador, el mouse simplemente desapareció. No es hasta que vuelva a colocar el mouse en el cuadro delimitador de la página visible que el navegador sabe dónde está, y luego desencadena todas las acciones apropiadas basadas en movimiento (como mouseout).

0
  1. ¿Por qué no el navegador no puede capturar de forma fiable el evento mouseout? Si puedo decir de manera confiable cuándo el mouse dejó el div usando la solución anterior, ¿por qué el navegador no puede hacerlo?

    creo que su respuesta es éste mismo cuando dijo:

    En comparación con dejar que el navegador hacer todo esto de forma nativa, realizando cálculos en cada movimiento píxel es un poco de un impacto en el rendimiento.

    El navegador no interpola entre los cuadros, por lo tanto, como dijiste exigiría muchos más recursos y memoria, por lo que no es "fijo".

  2. Si algunos movimientos de píxeles se pierden al igual que el ratón cruza el límite de la div, ¿por qué se sigue que el evento mouseout también debe omitir? Cuando el navegador finalmente comienza a registrar la posición del mouse nuevamente (después de un movimiento rápido repentino), incluso si el mouse está ahora a millas fuera del cuadro, el punto es que solía estar en el cuadro y ya no está. Entonces, ¿por qué no dispara el evento mouseout entonces?

    No lo sé con certeza, pero no creo que sea una condición de "estaba dentro y ahora está afuera". En cambio, es si cruza ese límite (si es MouseX - ElemOffsetX= 1). Estoy de acuerdo, no tiene tanto sentido, pero podría ser porque si estableces el valor en > 1, desencadenaría el evento varias veces. De lo contrario, tendría que hacer un seguimiento de los eventos, lo cual no está en la naturaleza de JS, ya que solo agrega eventos asincronizados a una pila.


Lo que se podría tratar de usar jQuery's mouseleave event. Esto hace dos cosas, lo que retrasa la activación del evento:

  1. que atraviesa el árbol DOM para ver si realmente dejó el elemento
  2. Creo que implementa una llamada de tiempo de espera, que debe resolver el problema de interpolación que lo notaste.
0

Su pregunta y la falta de otras respuestas claras me resultaron útiles porque me dijeron que tenía que crear una solución alternativa. Lo hice usando las ideas presentadas en su pregunta y los otros colaboradores.

Tengo mismo problema cuando uso jquery elem.bind mouseleave ('mouseleave', datos, mouseLeavesZone);

El problema es intermitente y puede estar relacionado con una CPU ocupada en el cliente. Digamos, por ejemplo, que la CPU está ocupada en otro lugar cuando el mouse se mueve fuera de un div. Entonces parece lógico que esta pueda ser la causa del error. Estoy de acuerdo; esto debería ser resuelto por los vendedores del navegador.

Ver http://jsfiddle.net/bgil2012/gWP5x/1/

(Aparte: Mi código jQuery necesita utilizar métodos jQuery mayores, ya que tiene que ejecutar en Drupal 7 que está ejecutando jQuery 1.4, en este momento y sin aplicar los parches que vienen).

1

me encontré con este problema un par de veces y me vinieron a aceptar la cuestión como un hecho de la vida. Pero depende de sus necesidades, puede usar CSS como yo lo hice. Por ejemplo, si solo quiero mostrar/ocultar una base de elemento en otro elemento que se encuentra suspendido, entonces CSS es el camino a seguir. Aquí es un trabajo, fiable ejemplo:

.large { 
    width: 175px; height: 175px; 
    position: absolute; 
    border-radius: 100%; 

    /*hide the glass by default*/ 
    top: -9999px; 
    left: -9999px; 
    opacity: 0; 
    transition: opacity .2s ease-in-out; 
    z-index: 100; 
    pointer-events: none; 
} 

.small:hover + .large { 
    opacity: 1; 
} 

http://codepen.io/tanduong/pen/aBMxyd

Cuestiones relacionadas