Как проверить, находится ли мышь над элементом в jQuery?

265

Есть ли быстрый и простой способ сделать это в jQuery, который мне не хватает?

Я не хочу использовать событие mouseover, потому что я уже использую его для чего-то другого. Мне просто нужно знать, находится ли мышь над элементом в данный момент.

Я хотел бы сделать что-то вроде этого, если бы только была функция "IsMouseOver":

function hideTip(oi) {
    setTimeout(function() { if (!IsMouseOver(oi)) $(oi).fadeOut(); }, 100);
}
Стив Уортэм
источник
5
Для большинства целей данных ответов достаточно, но бывают случаи, когда мышиный / не достаточно. Например, скрытие меню, когда мышь больше не находится ни над заголовком меню, ни над телом меню.
Маркус Даунинг
Я использовал метод, описанный в моем ответе, для работы с иконками (события мыши для границ кнопок), которые открывают анимированные выпадающие списки с отложенным закрытием. Вы обрабатываете задержку / отмену задержки как в значке, так и в раскрывающемся списке, используя методы triggerHandler в jquery. Вполне достаточно.
Mothmonsterman
# Маркус: Если вы прячете меню, что может быть лучше?
Coderama
Смотрите мой ответ stackoverflow.com/questions/9827095/…
Санне
Я бы проголосовал за это, если бы лучший ответ был отмечен как решение.
BBaysinger

Ответы:

97

Установите тайм-аут на mouseout для исчезновения и сохраните возвращаемое значение для данных в объекте. Затем onmouseover отмените тайм-аут, если в данных есть значение.

Удалить данные по обратному вызову затухания.

На самом деле дешевле использовать mouseenter / mouseleave, потому что они не запускаются для меню, когда стреляют mouseover / mouseout детей.

mothmonsterman
источник
7
@ Артур сделал прямо здесь, тебе все еще нужно больше информации? stackoverflow.com/a/1670561/152640
mothmonsterman
270

Этот код иллюстрирует то, что счастливое время Гарри и я пытаемся сказать. Когда мышь входит, появляется всплывающая подсказка, когда мышь уходит, она устанавливает задержку для ее исчезновения. Если мышь входит в тот же элемент до срабатывания задержки, то мы уничтожаем триггер, прежде чем он сработает, используя данные, которые мы сохранили ранее.

$("someelement").mouseenter(function(){
    clearTimeout($(this).data('timeoutId'));
    $(this).find(".tooltip").fadeIn("slow");
}).mouseleave(function(){
    var someElement = $(this),
        timeoutId = setTimeout(function(){
            someElement.find(".tooltip").fadeOut("slow");
        }, 650);
    //set the timeoutId, allowing us to clear this trigger if the mouse comes back over
    someElement.data('timeoutId', timeoutId); 
});
Артур Голдсмит
источник
245

Чистая и элегантная проверка при наведении:

if ($('#element:hover').length != 0) {
    // do something ;)
}
Иво
источник
6
точно - это должен быть выбранный ответ! Во всяком случае, вот скрипка для этого jsfiddle.net/mathheadinclouds/ZKGqe
mathheadinclouds
Как проверить, находится ли элемент в поиске: stackoverflow.com/questions/8981463/…
Кевин Уилер
126

ВНИМАНИЕ: is(':hover')не рекомендуется в jquery 1.8+. Смотрите этот пост для решения.

Вы также можете использовать этот ответ: https://stackoverflow.com/a/6035278/8843, чтобы проверить, находится ли мышь над элементом:

$('#test').click(function() {
    if ($('#hello').is(':hover')) {
        alert('hello');
    }
});
тал
источник
5
Это нигде не задокументировано (afik) и, похоже, не совсем точно с динамически отображаемыми элементами (например, меню) ..
lambinator
12
сломанный как jQuery 1.9.1! вместо этого используйте решение Ivo
mathheadinclouds
1
Uncaught Error: синтаксическая ошибка, нераспознанное выражение: неподдерживаемое псевдо: hover
Julio Marins
1
Предупреждение : :hoverнедопустимый селектор jQuery: api.jquery.com/category/selectors (источник: bugs.jquery.com/ticket/11574 )
Pang
1
Это все еще работает, если браузер поддерживаетdocument.querySelectorAll(':hover')
ekuusela
34

Вы можете использовать hoverсобытие jQuery для отслеживания вручную:

$(...).hover(
    function() { $.data(this, 'hover', true); },
    function() { $.data(this, 'hover', false); }
).data('hover', false);

if ($(something).data('hover'))
    //Hovered!
SLaks
источник
1
почему использовать data (), а не add / removeclass ()? Один более производительный, чем другой?
психотик
2
@psychotik: да; $.dataне включает в себя манипулирование строк
SLaks
Я обернул это в класс: stackoverflow.com/questions/1273566/…
ripper234
24

Мне нужно было что-то в точности как это (в немного более сложной среде и решение с большим количеством 'mouseenters' и 'mouseleaves' не работало должным образом), поэтому я создал небольшой плагин jquery, который добавляет метод ismouseover. До сих пор это работало довольно хорошо.

//jQuery ismouseover  method
(function($){ 
    $.mlp = {x:0,y:0}; // Mouse Last Position
    function documentHandler(){
        var $current = this === document ? $(this) : $(this).contents();
        $current.mousemove(function(e){jQuery.mlp = {x:e.pageX,y:e.pageY}});
        $current.find("iframe").load(documentHandler);
    }
    $(documentHandler);
    $.fn.ismouseover = function(overThis) {  
        var result = false;
        this.eq(0).each(function() {  
                var $current = $(this).is("iframe") ? $(this).contents().find("body") : $(this);
                var offset = $current.offset();             
                result =    offset.left<=$.mlp.x && offset.left + $current.outerWidth() > $.mlp.x &&
                            offset.top<=$.mlp.y && offset.top + $current.outerHeight() > $.mlp.y;
        });  
        return result;
    };  
})(jQuery);

Затем в любом месте документа вы называете его так, и он возвращает true или false:

$("#player").ismouseover()

Я протестировал его на IE7 +, Chrome 1+ и Firefox 4 и работает правильно.

Иван Кастелланос
источник
Кажется, он не работает на mouseenter (Chrome) - codepen.io/anon/pen/kcypB
wrygiel
Отлично. Сразу же вызывается выражение функции (IIFE), которое решает проблему нацеливания объектов под элементом с наложением непрозрачности. Brilliant! Спасибо тебе за это.
Александр Диксон
10

В jQuery вы можете использовать .is (': hover'), поэтому

function IsMouseOver(oi)
{
   return $(oi).is(':hover');
}

Теперь будет наиболее кратким способом обеспечить функцию, запрошенную в OP.

Примечание: выше не работает в IE8 или ниже

Как менее лаконичная альтернатива, которая работает в IE8 (если я могу доверять модусу IE8 в IE9) и делает это без $(...).hover(...)повсеместного срабатывания , и при этом не требует знания селектора для элемента (в этом случае ответ Ivo проще):

function IsMouseOver(oi)
{
    return oi.length && 
           oi.parent()
             .find(':hover')
             .filter(function(s){return oi[0]==this})
             .length > 0;
}
TOWR
источник
Это недействительный селектор jQuery! Люди должны перестать предлагать этот метод. Это везде и не совместимо с IE8.
Санне
Смотрите мой другой ответ, чтобы иметь решение для IE8
Sanne
2
@Sanne Это любопытно, потому $(':hover') что работает в IE8. Это действительный псевдо-селектор CSS2, поэтому он должен работать.
TOWR
7

Я взял идею SLaks и обернул ее в небольшой класс .

function HoverWatcher(selector){
  this.hovering = false;
  var self = this; 

  this.isHoveringOver = function() { 
    return self.hovering; 
  } 

    $(selector).hover(function() { 
      self.hovering = true; 
    }, function() { 
      self.hovering = false; 
    }) 
} 

var box1Watcher = new HoverWatcher('#box1');
var box2Watcher = new HoverWatcher('#box2');



$('#container').click(function() {
  alert("box1.hover = " + box1Watcher.isHoveringOver() +
        ", box2.hover = " + box2Watcher.isHoveringOver());
});
ripper234
источник
6

ТОЛЬКО FYI для будущих искателей этого.

Я сделал плагин JQuery, который может сделать это и многое другое. В моем плагине, чтобы получить все элементы, над которыми в данный момент находится курсор, просто сделайте следующее:

$.cursor("isHover"); // will return jQ object of all elements the cursor is 
                     // currently over & doesn't require timer

Как я уже упоминал, он также имеет множество других применений, как вы можете видеть в

jsFiddle найден здесь

SpYk3HH
источник
5

Поскольку я не могу комментировать, я напишу это как ответ!

Пожалуйста, поймите разницу между css selector ": hover" и событием hover!

": hover" является селектором css и действительно был удален вместе с событием при его использовании таким образом $("#elementId").is(":hover"), но это означает, что он не имеет никакого отношения к наведению на jQuery.

если вы кодируете $("#elementId:hover"), элемент будет выделен только при наведении курсора мыши. Вышеприведенный оператор будет работать со всеми версиями jQuery, так как вы выбираете этот элемент с чистым и законным выбором CSS.

С другой стороны, событие наведения, которое

$("#elementId").hover(
     function() { 
         doSomething(); 
     }
); 

действительно истолковывается как jQuery 1.8, здесь состояние с сайта jQuery:

Когда используется имя события «hover», подсистема событий преобразует его в «mouseenter mouseleave» в строке события. Это раздражает по нескольким причинам:

Семантика: зависание - это не то же самое, что мышь, входящая и выходящая из элемента, это подразумевает некоторое замедление или задержку перед выстрелом. Имя события: тип события. Возвращенный присоединенным обработчиком не является указателем, а указателем мыши или указателем мыши. Ни одно другое событие не делает этого. Кооптирование имени «hover»: невозможно прикрепить событие с именем «hover» и запустить его с помощью .trigger («hover»). Документы уже называют это имя «настоятельно не рекомендуется для нового кода», я хотел бы официально отказаться от него для 1.8 и в конечном итоге удалить его.

Почему они удалили использование (": hover") неясно, ну да ладно, вы все еще можете использовать его, как описано выше, и вот небольшой взлом, чтобы все еще использовать его.

(function ($) {
   /** 
    * :hover selector was removed from jQuery 1.8+ and cannot be used with .is(":hover") 
    * but using it in this way it works as :hover is css selector! 
    *
    **/
    $.fn.isMouseOver = function() {
        return $(this).parent().find($(this).selector + ":hover").length > 0;
    };
})(jQuery);

О, и я бы не рекомендовал версию с тайм-аутом, поскольку это приносит большую сложность , используйте функции тайм-аута для такого рода вещей, если нет другого пути, и поверьте мне, в 95% процентов всех случаев есть другой путь !

Надеюсь, я смогу помочь парочке людей там.

Привет Энди

феникс
источник
2

Спасибо вам обоим. В какой-то момент мне пришлось отказаться от попыток определить, была ли мышь все еще над элементом. Я знаю, что это возможно, но может потребоваться слишком много кода для выполнения.

Это заняло у меня немного времени, но я принял оба ваших предложения и придумал что-то, что сработало бы для меня.

Вот упрощенный (но функциональный) пример:

$("[HoverHelp]").hover (
    function () {
        var HelpID = "#" + $(this).attr("HoverHelp");
        $(HelpID).css("top", $(this).position().top + 25);
        $(HelpID).css("left", $(this).position().left);
        $(HelpID).attr("fadeout", "false");
        $(HelpID).fadeIn();
    },
    function () {
        var HelpID = "#" + $(this).attr("HoverHelp");
        $(HelpID).attr("fadeout", "true");
        setTimeout(function() { if ($(HelpID).attr("fadeout") == "true") $(HelpID).fadeOut(); }, 100);
    }
);

И затем, чтобы сделать эту работу над текстом, это все, что мне нужно сделать:

<div id="tip_TextHelp" style="display: none;">This help text will show up on a mouseover, and fade away 100 milliseconds after a mouseout.</div>

This is a <span class="Help" HoverHelp="tip_TextHelp">mouse over</span> effect.

Наряду с большим количеством причудливых CSS, это позволяет использовать очень полезные подсказки при наведении курсора. Кстати, мне понадобилась задержка при наведении мыши из-за крошечных промежутков между флажками и текстом, которые вызывали вспыхивающую подсказку при перемещении мыши. Но это работает как шарм. Я также сделал нечто подобное для событий фокусировки / размытия.

Стив Уортэм
источник
2

Я вижу, что для этого часто используются тайм-ауты, но в контексте события, вы не можете посмотреть на координаты, как это ?:

function areXYInside(e){  
        var w=e.target.offsetWidth;
        var h=e.target.offsetHeight;
        var x=e.offsetX;
        var y=e.offsetY;
        return !(x<0 || x>=w || y<0 || y>=h);
}

В зависимости от контекста вам может потребоваться убедиться (this == e.target) перед вызовом areXYInside (e).

fyi- Я рассматриваю использование этого подхода внутри обработчика dragLeave, чтобы подтвердить, что событие dragLeave не было вызвано входом в дочерний элемент. Если вы как-то не проверяете, что находитесь внутри родительского элемента, вы можете ошибочно предпринять действия, которые предназначены только для тех случаев, когда вы действительно покидаете родительский элемент.

РЕДАКТИРОВАТЬ: это хорошая идея, но не работает достаточно последовательно. Возможно, с некоторыми небольшими изменениями.

ДЛО
источник
2

Вы можете проверить, есть jQueryли у какого-либо дочернего div определенный класс. Затем, применяя этот класс при наведении курсора мыши на определенный элемент div, вы можете проверить, находится ли указатель мыши над ним, даже если вы наводите курсор мыши на другой элемент на странице. Я использовал это, потому что во всплывающем окне у меня были пробелы между элементами div, и я хотел закрывать всплывающее окно только тогда, когда я выходил из всплывающего окна, а не когда я перемещал мышь над пробелами во всплывающем окне. Поэтому я вызвал функцию наведения мыши на элементе содержимого (который закончил всплывающее окно), но он вызывал функцию закрытия только тогда, когда наложил содержимое на элемент содержимого, И был вне всплывающего окна!

$ ( "Выскакивающие"). Наведите курсор мыши (функция (е)
    {
    $ (Это) .addClass ( "за");
    });

$ ( "Выскакивающие"). MouseOut (функция (е)
    {
    $ (Это) .removeClass ( "за");
    });


$ ( "# MainContent"). Наведите курсор мыши (функция (е) {
            if (! $ (". extended"). hasClass ("over")) {
            Drupal.dhtmlMenu.toggleMenu ($ () "расширен.");
        }
    });

Nate
источник
2

Это был бы самый простой способ сделать это!

  function(oi) 
  {
   if(!$(oi).is(':hover')){$(oi).fadeOut(100);}
  }
Карима
источник
2

Вот техника, которая не опирается на jquery и использует собственный matches API DOM . Он использует префиксы вендоров для поддержки браузеров, возвращающихся к IE9. Смотрите matchselector на caniuse.com для более подробной информации.

Сначала создайте функцию matchSelector, вот так:

var matchesSelector = (function(ElementPrototype) {
var fn = ElementPrototype.matches ||
          ElementPrototype.webkitMatchesSelector ||
          ElementPrototype.mozMatchesSelector ||
          ElementPrototype.msMatchesSelector;

return function(element, selector) {
  return fn.call(element, selector);
};

})(Element.prototype);

Затем, чтобы обнаружить зависание:

var mouseIsOver = matchesSelector(element, ':hover');
Эндрю Ньюдигейт
источник
1

Я ответил на это в другом вопросе со всеми деталями, которые могут вам понадобиться:

Обнаружение наведения IF на элемент с помощью jQuery (имеет 99 голосов на момент написания)

По сути, вы можете сделать что-то вроде:

var ishovered = oi.is(":hover");

Это работает, только если oiэто объект jQuery, содержащий один элемент. Если сопоставлено несколько элементов, необходимо применить к каждому элементу, например:

var hoveredItem = !!$('ol>li').filter(function() { return $(this).is(":hover"); });
                  // not .filter(':hover'), as we can't apply :hover on multiple elements

Это было проверено начиная с jQuery 1.7.

Meligy
источник
1

Вот функция, которая помогает вам проверить, находится ли мышь внутри элемента или нет. Единственное, что вам нужно сделать, - это вызвать функцию, в которой вы можете иметь связанный с мышью EventObject. что-то вроде этого:

$("body").mousemove(function(event){
     element_mouse_is_inside($("#mycontainer", event, true, {});
});

Вы можете увидеть исходный код здесь, в github или внизу поста:

https://github.com/mostafatalebi/ElementsLocator/blob/master/elements_locator.jquery.js

function element_mouse_is_inside  (elementToBeChecked, mouseEvent, with_margin, offset_object)
{
    if(!with_margin)
    {
        with_margin = false;
    }
    if(typeof offset_object !== 'object')
    {
        offset_object = {};
    }
    var elm_offset = elementToBeChecked.offset();
    var element_width = elementToBeChecked.width();
    element_width += parseInt(elementToBeChecked.css("padding-left").replace("px", ""));
    element_width += parseInt(elementToBeChecked.css("padding-right").replace("px", ""));
    var element_height = elementToBeChecked.height();
    element_height += parseInt(elementToBeChecked.css("padding-top").replace("px", ""));
    element_height += parseInt(elementToBeChecked.css("padding-bottom").replace("px", ""));
    if( with_margin)
    {
        element_width += parseInt(elementToBeChecked.css("margin-left").replace("px", ""));
        element_width += parseInt(elementToBeChecked.css("margin-right").replace("px", ""));
        element_height += parseInt(elementToBeChecked.css("margin-top").replace("px", ""));
        element_height += parseInt(elementToBeChecked.css("margin-bottom").replace("px", ""));
    }

    elm_offset.rightBorder = elm_offset.left+element_width;
    elm_offset.bottomBorder = elm_offset.top+element_height;

    if(offset_object.hasOwnProperty("top"))
    {
        elm_offset.top += parseInt(offset_object.top);
    }
    if(offset_object.hasOwnProperty("left"))
    {
        elm_offset.left += parseInt(offset_object.left);
    }
    if(offset_object.hasOwnProperty("bottom"))
    {
        elm_offset.bottomBorder += parseInt(offset_object.bottom);
    }
    if(offset_object.hasOwnProperty("right"))
    {
        elm_offset.rightBorder += parseInt(offset_object.right);
    }
    var mouseX = mouseEvent.pageX;
    var mouseY = mouseEvent.pageY;

    if(  (mouseX > elm_offset.left && mouseX < elm_offset.rightBorder)
        && (mouseY > elm_offset.top && mouseY < elm_offset.bottomBorder) )
    {
        return true;
    }
    else
    {
        return false;
    }
}
Мостафа Талеби
источник
0

Продолжая то, что сказал «Happytime harry», обязательно используйте функцию .data () jquery для хранения идентификатора тайм-аута. Это сделано для того, чтобы вы могли очень легко получить идентификатор тайм-аута, когда «mouseenter» будет запущен на том же элементе позже, что позволит вам устранить триггер для исчезновения всплывающей подсказки.

Артур Голдсмит
источник
0

Вы можете использовать jQuery mouseenter и mouseleave. Вы можете установить флаг, когда мышь входит в нужную область, и снять флаг, когда она покидает область.

mikerobi
источник
1
Вот о чем я думал. Использование $ .data (), как предлагает SLaks, кажется хорошим способом для достижения этой цели.
JamesBrownIsDead
0

Я объединил идеи из этой темы и придумал это, что полезно для показа / скрытия подменю:

$("#menu_item_a").mouseenter(function(){
   clearTimeout($(this).data('timeoutId'));
   $("#submenu_a").fadeIn("fast");
}).mouseleave(function(){
   var menu_item = $(this);

   var timeoutId = setTimeout(function(){
      if($('#submenu_a').is(':hover'))
      {
        clearTimeout(menu_item.data('timeoutId'));
      }
      else
      {
        $("#submenu_a").fadeOut("fast");
      }
   }, 650);

    menu_item.data('timeoutId', timeoutId); 
});

 $("#submenu_a").mouseleave(function(){
   $(this).fadeOut("fast");
 });

Кажется, работает на меня. Надеюсь, это кому-нибудь поможет.

РЕДАКТИРОВАТЬ: Теперь реализация этого подхода не работает правильно в IE.

Два пирса
источник
0

Я не мог использовать ни одно из предложений выше.
Почему я предпочитаю свое решение?
Этот метод проверяет, находится ли мышь над элементом в любое время, выбранное Вами .
Mouseenter и : hover - это круто, но mouseenter срабатывает только при перемещении мыши, а не когда элемент перемещается под мышью.
: hover довольно милый, но ... IE

Итак, я делаю это:

№ 1. сохраняйте положение мыши x, y при каждом ее перемещении, когда вам нужно,
№ 2. проверяйте, находится ли мышь над любым из элементов, соответствующих запросу, что-то делает ... например, вызывает событие mouseenter

// define mouse x, y variables so they are traced all the time
var mx = 0; //  mouse X position
var my = 0; //  mouse Y position

// update mouse x, y coordinates every time user moves the mouse
$(document).mousemove(function(e){
    mx = e.pageX;
    my = e.pageY;
});

// check is mouse is over an element at any time You need (wrap it in function if You need to)
$("#my_element").each(function(){
    boxX = $(this).offset().left;
    boxY = $(this).offset().top;
    boxW = $(this).innerWidth();
    boxH = $(this).innerHeight();
    if ((boxX <= mx) &&
        (boxX + 1000 >= mx) &&
        (boxY <= my) &&
        (boxY + boxH >= my))
    {
        // mouse is over it so you can for example trigger a mouseenter event
        $(this).trigger("mouseenter");
    }
});
Гипер Движение
источник
0

Просто заметка о популярном и полезном ответе Артура Голдсмита выше: если вы перемещаете указатель мыши от одного элемента к другому в IE (по крайней мере до IE 9), у вас могут возникнуть некоторые проблемы, чтобы заставить его работать правильно, если новый элемент имеет прозрачный фон (который будет по умолчанию). Мой обходной путь - дать новому элементу прозрачное фоновое изображение.

Джиш
источник
0
$(document).hover(function(e) {
    alert(e.type === 'mouseenter' ? 'enter' : 'leave');
});

FIDDLE

yckart
источник
-1

Ты можешь использовать is(':visible'); в jquery. И для $ ('. Item: hover') это работает и в Jquery.

это сниметет код htm:

    <li class="item-109 deeper parent">
<a class="root" href="/Comsopolis/index.php/matiers"><span>Matiers</span></a>
<ul>
<li class="item-110 noAff">
<a class=" item sousMenu" href="/Comsopolis/index.php/matiers/tsdi">
<span>Tsdi</span>
</a>
</li>
<li class="item-111 noAff">
<a class="item" href="/Comsopolis/index.php/matiers/reseaux">
<span>Réseaux</span>
</a>
</li>
</ul>
</li>

и это код JS:

$('.menutop > li').hover(function() {//,.menutop li ul

    $(this).find('ul').show('fast');

},function() {
    if($(this).find('ul').is(':hover'))
    $(this).hide('fast');

});

 $('.root + ul').mouseleave(function() {
    if($(this).is(':visible'))
    $(this).hide('fast');

});

это то, о чем я говорил :)

ucefkh
источник
1
Я не вижу, как это связано с заданным вопросом.
Эндрю Барбер
Вы можете использовать это, когда выходите из мыши и отображаете скрытый элемент, и после задержки вы можете проверить, видна ли она, когда мышь входит в целевой элемент, который вы хотите скрыть / показать
ucefkh
1
Я не думаю, что вы читаете вопрос очень хорошо. Это совсем не то, что ему нужно.
Эндрю Барбер
1
То, что вы делаете, не связано с этим вопросом . (по-видимому (
Эндрю Барбер