Detecta IF pasando el cursor sobre el elemento con jQuery

150

No estoy buscando una acción para llamar al pasar el ratón, sino una forma de saber si un elemento se está pasando por encima actualmente. Por ejemplo:

$('#elem').mouseIsOver(); // returns true or false

¿Existe un método jQuery que logre esto?

James Skidmore
fuente
En caso de que alguien esté buscando otras soluciones stackoverflow.com/questions/1273566/…
Jo E.
1
La marca como duplicado parece bastante incorrecta. La pregunta no dice cuál es la intención, para que otra persona lea la mente del OP y decida que es una pregunta de detección de colisión y la marca como duplicada.
Meligy

Respuestas:

306

Respuesta original (y correcta):

Puede usar is()y verificar el selector :hover.

var isHovered = $('#elem').is(":hover"); // returns true or false

Ejemplo: http://jsfiddle.net/Meligy/2kyaJ/3/

(Esto solo funciona cuando el selector coincide con UN elemento como máximo. Consulte Editar 3 para obtener más información)

.

Edición 1 (29 de junio de 2013): (Aplicable solo a jQuery 1.9.x, ya que funciona con 1.10+, consulte la siguiente Edición 2)

Esta respuesta fue la mejor solución en el momento en que se respondió la pregunta. Este selector ': hover' se eliminó con el .hover()método de eliminación en jQuery 1.9.x.

Curiosamente, una respuesta reciente de "allicarn" muestra que es posible usarlo :hovercomo selector CSS (frente a Sizzle) cuando lo prefijas con un selector $($(this).selector + ":hover").length > 0, ¡y parece que funciona!

Además, el complemento hoverIntent mencionado en otra respuesta también se ve muy bien.

Edición 2 (21 de septiembre de 2013): .is(":hover") funciona

Basado en otro comentario, noté que la forma original en que publiqué .is(":hover"), en realidad todavía funciona en jQuery, entonces.

  1. Funcionó en jQuery 1.7.x.

  2. Dejó de funcionar en 1.9.1, cuando alguien me lo informó, y todos pensamos que estaba relacionado con jQuery eliminando el hoveralias para el manejo de eventos en esa versión.

  3. Funcionó nuevamente en jQuery 1.10.1 y 2.0.2 (quizás 2.0.x), lo que sugiere que la falla en 1.9.x fue un error o no un comportamiento intencional como pensamos en el punto anterior.

Si desea probar esto en una versión particular de jQuery, simplemente abra el ejemplo de JSFidlle al comienzo de esta respuesta, cambie a la versión de jQuery deseada y haga clic en "Ejecutar". Si el color cambia al pasar el mouse, funciona.

.

Edición 3 (9 de marzo de 2014): solo funciona cuando la secuencia jQuery contiene un único elemento

Como lo mostró @Wilmer en los comentarios, tiene un violín que ni siquiera funciona contra las versiones de jQuery con las que yo y otros aquí lo probamos. Cuando traté de encontrar lo especial de su caso, noté que estaba tratando de verificar múltiples elementos a la vez. Esto fue arrojar Uncaught Error: Syntax error, unrecognized expression: unsupported pseudo: hover.

Entonces, trabajando con su violín, esto NO funciona:

var isHovered = !!$('#up, #down').filter(":hover").length;

Si bien esto DOES trabajo:

var isHovered = !!$('#up,#down').
                    filter(function() { return $(this).is(":hover"); }).length;

También funciona con secuencias jQuery que contienen un solo elemento, como si el selector original coincidiera con un solo elemento, o si llamara .first()a los resultados, etc.

Esto también se menciona en mi Boletín de recursos y sugerencias de desarrollo web de JavaScript + .

Meligy
fuente
1
Funciona genial, simple. Gracias Mohamed!
James Skidmore
18
Emite un error en IE 8: Syntax Error, unrecognized expression: hover. jquery-1.7.js line 4179.
RobG
Es verdad. Solo lo probé. Para IE6, intente este truco descrito aquí peterned.home.xs4all.nl/csshover.html o vuelva al estado normal, agregue algún estado y borre más tarde un tipo de solución.
Meligy
1
@Meligy: bifurqué tu violín para ilustrar que no funciona con varios elementos en la selección: jsfiddle.net/p34n8
SuperNova
1
Además, si está utilizando jQuery mobile, eso también lo arruina: verifique la respuesta del violín en gideons y active la casilla jQuery Mobile 1.4.4 y puede ver que no funciona, entonces ... puedo confirmar que es lo mismo con 1.4.2 también :(
David O'Sullivan
32

Utilizar:

var hovered = $("#parent").find("#element:hover").length;

jQuery 1.9+

usuario2444818
fuente
1
Esto funciona brillantemente bien. La mejor solución encontrada al buscar un reemplazo para la función .hover y: selector de desplazamiento. ¡Gracias!
Tyler
1
¡Funciona de maravilla! :)
jroi_web
9

No funciona en jQuery 1.9. Hizo este complemento basado en la respuesta del usuario 2444818.

jQuery.fn.mouseIsOver = function () {
    return $(this).parent().find($(this).selector + ":hover").length > 0;
}; 

http://jsfiddle.net/Wp2v4/1/

allicarn
fuente
5

Establecer una bandera al pasar el ratón:

var over = false;
$('#elem').hover(function() {
  over = true;
},
function () {
  over = false;
});

Entonces solo revisa tu bandera.

kinakuta
fuente
Simple, pero no fácilmente reutilizable. : /
Trevor
No parecía funcionar en mi situación particular, pero estoy de acuerdo en que es una buena manera de hacerlo. En mi caso, cuando tengo mouseleaveun elemento, quiero verificar si el mouse ingresó a otro elemento en particular.
James Skidmore
@JamesSkidmore: en el evento mouseleave puede usar e.fromElementy e.toElement. ¿Funcionará para ti?
mrtsherman
Puede actualizar esto para usar un selector que cubra todos los elementos aplicables y almacenar la bandera en los elementos individuales usando .data().
nnnnnn
@Trevor - verdadero - necesitaría almacenar el estado en el elemento y luego crear una función que verifique el estado del elemento (presumiblemente etiqueta de datos).
kinakuta
4

Un par de actualizaciones para agregar después de trabajar en este tema por un tiempo:

  1. todas las soluciones con .is (": hover") se rompen en jQuery 1.9.1
  2. La razón más probable para verificar si el mouse todavía está sobre un elemento es intentar evitar que los eventos se disparen unos sobre otros. Por ejemplo, estábamos teniendo problemas con la activación y finalización de nuestro mouseleave antes de que nuestro evento mouseenter se completara. Por supuesto, esto se debió a un rápido movimiento del mouse.

Utilizamos hoverIntent https://github.com/briancherne/jquery-hoverIntent para resolver el problema por nosotros. Esencialmente, se dispara si el movimiento del mouse es más deliberado. (Una cosa a tener en cuenta es que activará tanto el mouse que ingresa un elemento como si se va, si solo desea usar una pasada, el constructor una función vacía)

Donald A Nummer Jr
fuente
4

Puede filtrar su elemento de todos los elementos suspendidos. Código problemático

element.filter(':hover')

Guardar código:

jQuery(':hover').filter(element)

Para devolver booleano:

jQuery(':hover').filter(element).length===0
Miño
fuente
4

La respuesta aceptada no funcionó para mí en JQuery 2.x .is(":hover")devuelve falso en cada llamada.

Terminé con una solución bastante simple que funciona:

function isHovered(selector) {

    return $(selector+":hover").length > 0

}
gidim
fuente
3

Ampliando la respuesta de @ Mohamed. Podrías usar un poco de encapsulación

Me gusta esto:

jQuery.fn.mouseIsOver = function () {
    if($(this[0]).is(":hover"))
    {
        return true;
    }
    return false;
}; 

Úselo como:

$("#elem").mouseIsOver();//returns true or false

Bifurcado el violín: http://jsfiddle.net/cgWdF/1/

Gedeón
fuente
66
para hacerlo, también podría hacer: jQuery.fn.mouseIsOver = function () {return $ (this [0]). is (': hover')}; menos código
Lathan
32
lo difícil que es simplemente hacer $ ('# elem'). is (': hover')
luckykrrish
No es una cuestión difícil, pero más bien, la intención se expresa claramente. Pero para cada uno es propio.
Gedeón
1

Me gusta la primera respuesta, pero para mí es raro. Cuando intento verificar justo después de cargar la página para el mouse, tengo que poner al menos un retraso de 500 milisegundos para que funcione:

$(window).on('load', function() {
    setTimeout(function() {
        $('img:hover').fadeOut().fadeIn();
    }, 500);
});

http://codepen.io/molokoloco/pen/Grvkx/

molokoloco
fuente
0

Establecer una bandera por la respuesta de kinakuta parece razonable, puede poner un oyente en el cuerpo para que pueda verificar si algún elemento se desplaza en un instante en particular.

Sin embargo, ¿cómo quiere lidiar con los nodos secundarios? Tal vez debería verificar si el elemento es un ancestro del elemento actualmente suspendido.

<script>

var isOver = (function() {
  var overElement;
  return {

    // Set the "over" element
    set: function(e) {
      overElement = e.target || e.srcElement;
    },

    // Return the current "over" element
    get: function() {
      return overElement;    
    },

    // Check if element is the current "over" element
    check: function(element) {
      return element == overElement;
    },

    // Check if element is, or an ancestor of, the 
    // current "over" element
    checkAll: function(element) {
      while (overElement.parentNode) {
         if (element == overElement) return true;
         overElement = overElement.parentNode;
      }
      return false;
    }
  };
}());


// Check every second if p0 is being hovered over
window.setInterval( function() {
  var el = document.getElementById('p0');
  document.getElementById('msg').innerHTML = isOver.checkAll(el);
}, 1000);


</script>

<body onmouseover="isOver.set(event);">
  <div>Here is a div
    <p id="p0">Here is a p in the div<span> here is a span in the p</span> foo bar </p>
  </div>
  <div id="msg"></div>
</body>
RobG
fuente