Як перевірити, чи миша перебуває над елементом jQuery?


265

Чи є швидкий і простий спосіб зробити це в jQuery, який мені не вистачає?

Я не хочу використовувати подію миші, тому що я вже використовую її для чогось іншого. Мені просто потрібно знати, чи миша перебуває над елементом в даний момент.

Я хотів би зробити щось подібне, якби тільки була функція "IsMouseOver":

function hideTip(oi) {
    setTimeout(function() { if (!IsMouseOver(oi)) $(oi).fadeOut(); }, 100);
}

5
Для більшості цілей наведених відповідей достатньо, але є випадки, коли миші / виходу недостатньо. Наприклад, приховування меню, коли миша більше не над головою меню АБО тілом меню.
Маркус Даунінг

Я використав метод, описаний у своїй відповіді, для роботи з піктограмами (події миші для меж кнопок), які відкривають анімовані, затримки закриття спадніх панелей. Ви обробляєте затримку / скасування затримки як у піктограмі, так і у спадному меню, використовуючи методи тригера jQery. Цілком достатньо.
mothmonsterman

# Маркус: Якщо ви ховаєте меню, то який спосіб краще зробити?
кодерама

Дивіться мою відповідь stackoverflow.com/questions/9827095/…
Sanne

Я би проголосував за це, якби найкраща відповідь була позначена як рішення.
BBaysinger

Відповіді:


97

Встановіть тайм-аут на миші, щоб згасати і зберігати повернене значення для даних в об'єкті. Потім, перейдіть мишею, скасуйте час очікування, якщо в даних є значення.

Видаліть дані про зворотний виклик стимулятора.

Насправді дешевше використовувати mouseenter / mouseleave, тому що вони не спрацьовують у меню, коли діти перемикають миші / mouseout.


7
@Arthur зробив тут, вам ще потрібна додаткова інформація? 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); 
});


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 !! використовуйте замість цього рішення Іво
mathheadinclouds

1
Неприхована помилка: Помилка синтаксису, нерозпізнаний вираз: непідтримуваний псевдо: 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!

1
навіщо використовувати дані (), а не додавати / видаляти клас ()? Чи один з виконавців більше, ніж інший?
психотік

2
@psychotik: Так; $.dataне передбачає маніпуляції з рядком.
СЛАкс

Я обернув це в класі: stackoverflow.com/questions/1273566 / ...
ripper234

24

Мені потрібно було щось саме так (у трохи складнішому середовищі та рішення з великою кількістю «мишецентрів» та «мишолов» не працювало належним чином), тому я створив невеликий плагін 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);

Тоді в будь-якому місці документа викличте його так, і він поверне справжнє або хибне:

$("#player").ismouseover()

Я перевірив його на IE7 +, Chrome 1+ та Firefox 4 і працює належним чином.


Схоже, це не працює на mouseenter (Chrome) - codepen.io/anon/pen/kcypB
wrygiel

Ідеально. Негайно викликається вираз функції (IIFE), який вирішує питання націлювання об'єктів під елементом із накладенням непрозорості. Блискуче! Дякую за це.
Олександр Діксон

10

У jQuery ви можете використовувати .is (': наведення'), так

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

зараз було б найбільш стислим способом надання функції, яка вимагається в ОП.

Примітка. Вищезазначене не працює в IE8 або нижче

Як менш лаконічна альтернатива, яка працює в IE8 (якщо я можу довіряти IE8 модулю IE8), і робить це, не запускаючи $(...).hover(...)всюди , і не вимагаючи знань селектора для цього елемента (у такому випадку відповідь Іво простіше):

function IsMouseOver(oi)
{
    return oi.length && 
           oi.parent()
             .find(':hover')
             .filter(function(s){return oi[0]==this})
             .length > 0;
}

Це недійсний селектор jQuery! Люди повинні припинити пропонувати цей метод. Він скрізь і не сумісний з IE8.
Sanne

Дивіться мою іншу відповідь, щоб мати рішення для IE8
Sanne,

2
@Sanne Цікаво, адже $(':hover') це працює в IE8. Це дійсний псевдоселектор CSS2, тому він повинен працювати.
буксир

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());
});

6

ПЕРЕГЛЯДУЙТЕ FYI для майбутніх шукачів цього.

Я зробив плагін jQuery, який може це зробити та багато іншого. У моєму плагіні, щоб отримати всі елементи, над якими курсор перебуває зараз, просто виконайте наступне:

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

Як я вже згадував, він також має багато інших застосувань, як ви можете бачити в

Тут знайдено jsFiddle


5

Як я не можу коментувати, тому напишу це як відповідь!

Будь ласка, зрозумійте різницю між css-селектором ": hover" та подією hover!

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

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

З іншого боку, подія, що є

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

насправді застаріло як jQuery 1.8, тут стан із веб-сайту jQuery:

Коли використовується подія "hover", підсистема події перетворює її в "mouseenter mouseleave" у рядку події. Це дратує з кількох причин:

Семантика: Наведення вказівника не є тим, що миша вводить і залишає елемент, це передбачає деяку кількість уповільнення або затримки перед стрільбою. Назва події: Тип події event.type, що повертається приєднаним оброблювачем, не наведення курсору, а або миші, або миші. Жодна інша подія цього не робить. Кооптування імені "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);
}

Залежно від контексту, можливо, вам доведеться переконатися (це == e.target) перед тим, як викликатиXXInside (e).

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

EDIT: це хороша ідея, але працює недостатньо послідовно. Можливо, з якимись дрібними поправками.


2

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

$ (". спливаюче вікно"). миша (функція (e)
    {
    $ (this) .addClass ("понад");
    });

$ (". спливаюче вікно"). mouseout (функція (e)
    {
    $ (це) .removeClass ("понад");
    });


$ ("# mainContent"). перемикання миші (функція (e) {
            if (! $ (". extension"). hasClass ("over")) {
            Drupal.dhtmlMenu.toggleMenu ($ (". Розширено"));
        }
    });


2

Це був би найпростіший спосіб зробити це!

  function(oi) 
  {
   if(!$(oi).is(':hover')){$(oi).fadeOut(100);}
  }

2

Ось методика, яка не покладається на jquery та використовує нативний DOM matches API . Він використовує префікси постачальників для підтримки браузерів, що повертаються до 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.


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", обов'язково використовуйте функцію jquery .data () для збереження ідентифікатора часу. Це так, що ви можете дуже легко отримати ідентифікатор очікування, коли пізніше на цьому ж елементі буде запущено "mouseenter", що дозволить вам усунути тригер для зникнення підказки.


0

Ви можете використовувати події миші у центрі jQuery та події миші. Ви можете встановити прапор, коли миша входить до потрібної області, а скинути прапор, коли він покине область.


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");
 });

Здається, працює для мене. Сподіваюся, що це комусь допоможе.

EDIT: Зараз усвідомлення цього підходу не працює належним чином в IE.


0

Я не міг використати жодну з наведених вище пропозицій.
Чому я віддаю перевагу своєму рішенню?
Цей метод перевіряє, чи миша перебуває над елементом у будь-який обраний Вами час .
Mouseenter і : наведіть курсор , але курсор спрацьовує лише в тому випадку, якщо ви переміщуєте мишу, а не тоді, коли елемент переміщується під мишею.
: Ховер досить милий, але ... IE

Тому я роблю це:

Ні 1. магазин миші х, у позиції кожен раз , коли він переміщається , коли вам потрібно,
№ 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), у вас можуть виникнути проблеми з коректною роботою, якщо новий елемент має прозорий фон (який був би за замовчуванням). Моє вирішення полягало в тому, щоб надати новому елементу прозоре фонове зображення.



-1

Ви можете використовувати is(':visible');в jquery And для $ ('. Item: hover'), він також працює в Jquery.

це snnipet 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');

});

це те, про що я говорив :)


1
Я не бачу, як це пов’язано із заданим питанням.
Ендрю Барбер

Ви можете використовувати це, коли ви виходите з курсору миші та показуєте прихований елемент, а після затримки ви можете перевірити, чи це видно, коли миша вводить цільовий елемент, який ви хочете приховати / показати
ucefkh

1
Я не думаю, що ти зовсім добре читаєш питання. Це зовсім не те, що йому потрібно.
Ендрю Барбер

1
Те, що ви робите, не пов’язане з цим питанням . (мабуть (
Ендрю Барбер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.