Detectar SE pairando sobre o elemento com jQuery

150

Não estou procurando uma ação para chamar ao passar o mouse, mas uma maneira de saber se um elemento está passando o mouse sobre o assunto atualmente. Por exemplo:

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

Existe um método jQuery que realiza isso?

James Skidmore
fonte
Apenas no caso de alguém estar procurando outras soluções, stackoverflow.com/questions/1273566/…
Jo E.
1
A marcação como duplicada parece bastante errada. A pergunta não diz qual é a intenção, para alguém ler a mente do OP e decidir que é uma pergunta de detecção de colisão e marcar como duplicada.
precisa saber é o seguinte

Respostas:

306

Resposta original (e correta):

Você pode usar is()e verificar o seletor :hover.

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

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

(Isso funciona apenas quando o seletor corresponde a UM elemento no máximo. Consulte Editar 3 para obter mais informações)

.

Edit 1 (29 de junho de 2013): (Aplicável apenas ao jQuery 1.9.x, pois funciona com 1.10 ou superior, consulte o próximo Edit 2)

Esta resposta foi a melhor solução no momento em que a pergunta foi respondida. Esse seletor ': hover' foi removido com a .hover()remoção do método no jQuery 1.9.x.

Curiosamente, uma resposta recente de "allicarn" mostra que é possível usar :hovercomo seletor CSS (vs. Sizzle) quando você o prefixa com um seletor $($(this).selector + ":hover").length > 0, e parece funcionar!

Além disso, o plugin hoverIntent mencionado em outra resposta também parece muito bom.

Edit 2 (21 de setembro de 2013): .is(":hover") obras

Com base em outro comentário, notei que a maneira original que eu publiquei .is(":hover"), na verdade ainda funciona no jQuery, então.

  1. Funcionou no jQuery 1.7.x.

  2. Ele parou de funcionar no 1.9.1, quando alguém me informou, e todos pensamos que estava relacionado ao jQuery remover o hoveralias para manipulação de eventos nessa versão.

  3. Funcionou novamente no jQuery 1.10.1 e 2.0.2 (talvez 2.0.x), o que sugere que a falha no 1.9.x foi um bug ou, portanto, não um comportamento intencional, como pensamos no ponto anterior.

Se você quiser testar isso em uma versão específica do jQuery, basta abrir o exemplo JSFidlle no início desta resposta, mude para a versão desejada do jQuery e clique em "Executar". Se a cor mudar ao passar o mouse, funciona.

.

Edit 3 (9 de março de 2014): Funciona apenas quando a sequência jQuery contém um único elemento

Como mostra @Wilmer nos comentários, ele tem um violino que nem funciona contra as versões do jQuery que eu e outros aqui testamos. Quando tentei descobrir o que há de especial no caso dele, notei que ele estava tentando verificar vários elementos ao mesmo tempo. Isso estava jogando Uncaught Error: Syntax error, unrecognized expression: unsupported pseudo: hover.

Então, trabalhando com seu violino, isso NÃO funciona:

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

Enquanto isso FAZ trabalho:

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

Também funciona com sequências jQuery que contêm um único elemento, como se o seletor original correspondesse a apenas um elemento ou se você solicitou .first()os resultados, etc.

Isso também é mencionado no meu boletim JavaScript + Dicas e recursos do desenvolvedor da Web .

Meligy
fonte
1
Funciona muito bem, simples. Obrigado Mohamed!
James Skidmore
18
Gera um erro no IE 8: Syntax Error, unrecognized expression: hover. jquery-1.7.js line 4179.
RobG
Isso é verdade. Apenas testei. Para o IE6, tente este hack descrito aqui peterned.home.xs4all.nl/csshover.html ou volte ao hover normal, adicione algum estado e limpe o tipo de solução mais tarde.
precisa saber é
1
@Meligy: Eu bifurcada seu violino para ilustrar que ele não está funcionando com vários itens na seleção: jsfiddle.net/p34n8
SuperNova
1
Além disso, se você estiver usando o jQuery mobile, isso também estraga tudo - verifique o violino na resposta do gideons e ative a caixa do jQuery Mobile 1.4.4 e você pode ver que não funciona então ... Posso confirmar o mesmo com 1.4.2 também :(
David O'Sullivan
32

Usar:

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

jQuery 1.9+

user2444818
fonte
1
Isso funciona brilhantemente bem. Melhor solução encontrada ao procurar uma substituição para a função .hover e: hover selector. Obrigado!
Tyler
1
Funciona como um encanto! :)
jroi_web
9

Não funciona no jQuery 1.9. Criou este plugin com base na resposta do usuário2444818.

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

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

allicarn
fonte
5

Defina uma bandeira ao passar o mouse:

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

Em seguida, basta verificar sua bandeira.

kinakuta
fonte
Simples, mas não facilmente reutilizado. : /
Trevor
Não parecia funcionar na minha situação particular, mas concordo que é um bom caminho a percorrer. No meu caso, quando eu mouseleavetiver um elemento, quero verificar se o mouse inseriu outro elemento em particular.
James Skidmore
@JamesSkidmore - no evento mouseleave você pode usar e.fromElemente e.toElement. Será que isso funciona para você?
mrtsherman
Você pode atualizar isso para usar um seletor que cubra todos os elementos aplicáveis ​​e armazenar o sinalizador nos elementos individuais usando .data().
Nnnnnn
@Trevor - true - você precisaria armazenar o estado no elemento e criar uma função que verifique o estado (presumivelmente de tag de dados) do elemento.
precisa saber é
4

Algumas atualizações a serem adicionadas depois de trabalhar um pouco sobre esse assunto:

  1. todas as soluções com .is (": hover") são interrompidas no jQuery 1.9.1
  2. O motivo mais provável para verificar se o mouse ainda está sobre um elemento é tentar impedir que eventos sejam disparados um sobre o outro. Por exemplo, estávamos tendo problemas com o fato de nossa ratoeira ser acionada e concluída antes mesmo que nosso evento de mouseenter fosse concluído. Claro que isso foi por causa de um rápido movimento do mouse.

Usamos o hoverIntent https://github.com/briancherne/jquery-hoverIntent para resolver o problema. Essencialmente, ele dispara se o movimento do mouse for mais deliberado. (uma coisa a ser observada é que ele será acionado com o mouse entrando em um elemento e saindo - se você quiser usar apenas uma passagem ao construtor, uma função vazia)

Donald A Nummer Jr
fonte
4

Você pode filtrar seu elemento de todos os elementos pairados. Código problemático:

element.filter(':hover')

Salvar código:

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

Para retornar booleano:

jQuery(':hover').filter(element).length===0
Mino
fonte
4

A resposta aceita não funcionou para mim no JQuery 2.x .is(":hover")retorna falso em todas as chamadas.

Acabei com uma solução bastante simples que funciona:

function isHovered(selector) {

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

}
gidim
fonte
3

Expandindo a resposta de @ Mohamed. Você poderia usar um pouco de encapsulamento

Como isso:

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

Use-o como:

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

Bifurcou o violino: http://jsfiddle.net/cgWdF/1/

gideon
fonte
6
para fazer isso, você também pode: jQuery.fn.mouseIsOver = function () {return $ (this [0]). is (': hover')}; menos código
Lathan 14/11
32
quão difícil é simplesmente fazer $ ( '# elem') é ( ': hover').
luckykrrish
não é uma questão difícil, mas mais a intenção é claramente expressa. Mas para cada um é próprio.
gideon
1

Eu gosto da primeira resposta, mas para mim é estranho. Ao tentar verificar logo após o carregamento da página o mouse, tenho que colocar pelo menos um atraso de 500 milissegundos para que ele funcione:

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

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

molokoloco
fonte
0

Definir uma sinalização de acordo com a resposta de kinakuta parece razoável, você pode colocar um ouvinte no corpo para verificar se algum elemento está passando o mouse sobre um determinado momento.

No entanto, como você deseja lidar com nós filhos? Talvez você deva verificar se o elemento é um ancestral do elemento atualmente pairado.

<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
fonte