Как я могу проверить, находится ли мышь над элементом в jQuery?
Есть ли быстрый и простой способ сделать это в jQuery, который мне не хватает?
Я не хочу использовать событие mouseover, потому что я уже использую его для чего-то другого. Мне просто нужно знать, находится ли мышь над элементом в данный момент.
Я хотел бы сделать что-то вроде этого, если бы только была функция "IsMouseOver":
function hideTip(oi) {
setTimeout(function() { if (!IsMouseOver(oi)) $(oi).fadeOut(); }, 100);
}
26 ответов
Установите тайм-аут на mouseout для исчезновения и сохраните возвращаемое значение для данных в объекте. Затем onmouseover, отмените таймаут, если в данных есть значение.
Удалить данные по обратному вызову затухания.
На самом деле дешевле использовать mouseenter/mouseleave, потому что они не запускаются для меню, когда стреляют mouseover/mouseout детей.
Чистая и элегантная проверка при наведении:
if ($('#element:hover').length != 0) {
// do something ;)
}
Этот код иллюстрирует то, что happytime harry пытаемся сказать. Когда мышь входит, появляется всплывающая подсказка, когда мышь уходит, она устанавливает задержку для ее исчезновения. Если мышь входит в тот же элемент до срабатывания задержки, то мы уничтожаем триггер, прежде чем он сработает, используя данные, которые мы сохранили ранее.
$("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);
});
ПРЕДУПРЕЖДЕНИЕ: is(':hover')
устарела в jquery 1.8+. Смотрите этот пост для решения.
Вы также можете использовать этот ответ: /questions/2327784/jquery-proverit-sostoyanie-navedeniya-pered-zapuskom-zapuska/2327792#2327792 чтобы проверить, находится ли мышь над элементом:
$('#test').click(function() {
if ($('#hello').is(':hover')) {
alert('hello');
}
});
Вы можете использовать JQuery's hover
событие для отслеживания вручную:
$(...).hover(
function() { $.data(this, 'hover', true); },
function() { $.data(this, 'hover', false); }
).data('hover', false);
if ($(something).data('hover'))
//Hovered!
Мне нужно было что-то в точности как это (в немного более сложной среде и решение с большим количеством '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 и работает нормально.
В 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;
}
Я взял идею 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());
});
Поскольку я не могу комментировать, я напишу это как ответ!
Пожалуйста, поймите разницу между 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% процентов случаев есть другой способ!
Надеюсь, я смогу помочь паре людей.
Привет Энди
ТОЛЬКО FYI для будущих искателей этого.
Я сделал плагин JQuery, который может сделать это и многое другое. В моем плагине, чтобы получить все элементы, над которыми в данный момент находится курсор, просто сделайте следующее:
$.cursor("isHover"); // will return jQ object of all elements the cursor is
// currently over & doesn't require timer
Как я уже упоминал, он также имеет множество других применений, как вы можете видеть в
jsFiddle найден здесь
Вот техника, которая не опирается на 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');
Это был бы самый простой способ сделать это!
function(oi)
{
if(!$(oi).is(':hover')){$(oi).fadeOut(100);}
}
Спасибо вам обоим. В какой-то момент мне пришлось отказаться от попыток определить, была ли мышь все еще над элементом. Я знаю, что это возможно, но может потребоваться слишком много кода для выполнения.
Это заняло у меня немного времени, но я принял оба ваших предложения и придумал что-то, что сработало бы для меня.
Вот упрощенный (но функциональный) пример:
$("[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, это позволяет использовать очень полезные подсказки при наведении курсора. Кстати, мне понадобилась задержка при наведении мыши из-за крошечных промежутков между флажками и текстом, которые вызывали вспыхивающую подсказку при перемещении мыши. Но это работает как шарм. Я также сделал нечто подобное для событий фокусировки / размытия.
Я вижу, что для этого часто используются тайм-ауты, но в контексте события, вы не можете посмотреть на координаты, как это?:
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 не было вызвано входом в дочерний элемент. Если вы как-то не проверяете, что находитесь внутри родительского элемента, вы можете ошибочно предпринять действия, которые предназначены только для тех случаев, когда вы действительно покидаете родительский элемент.
РЕДАКТИРОВАТЬ: это хорошая идея, но не работает достаточно последовательно. Возможно, с небольшими изменениями.
Вы можете проверить с jQuery
если какой-либо дочерний div имеет определенный класс. Затем, применяя этот класс при наведении курсора мыши на определенный элемент div, вы можете проверить, находится ли указатель мыши над ним, даже если вы наводите курсор мыши на другой элемент на странице. Я использовал это, потому что во всплывающем окне у меня были пробелы между элементами div, и я хотел закрывать всплывающее окно только тогда, когда я выходил из всплывающего окна, а не когда я перемещал мышь над пробелами во всплывающем окне. Поэтому я вызвал функцию наведения мыши на элементе содержимого (который закончил всплывающее окно), но он вызывал функцию закрытия только тогда, когда наложил содержимое на элемент содержимого, И был вне всплывающего окна!
$ ("Выскакивающие"). MouseOver (функция (е) { $(Это).addClass("над"); }); $ ("Выскакивающие"). MouseOut (функция (е) { $(Это).removeClass("над"); }); $ ("# MainContent"). Наведите курсор мыши (функция (е){ if (!$(".extended").hasClass("over")) { Drupal.dhtmlMenu.toggleMenu($() "расширен."); } });
Я ответил на это в другом вопросе со всеми деталями, которые могут вам понадобиться:
Обнаружение наведения 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.
Вот функция, которая помогает вам проверить, находится ли мышь внутри элемента или нет. Единственное, что вам нужно сделать, - это вызвать функцию, в которой вы можете создать живой 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;
}
}
Использоватьevt.originalEvent.composedPath()
MouseEvent
дает массивHTMLElement
Мышь, с которой недавно общались. Последний элемент является самым внешним (т.е. он всегдаWindow
).
Событие мышиcomposedPath()
пример ниже:
Проверив этот массив на наличие вашего кликабельного элемента, вы узнаете, было ли наведение мыши на конкретный элемент...
$(window).on("mouseup", onMouseUp);
const $someButton = $("a.yourButton");
function onMouseUp(evt) {
const path = evt.originalEvent.composedPath();
if(path.indexOf($someButton[0]) !== -1){
// released mouse over button
}else{
// did not release mouse over button
}
}
Просто заметка о популярном и полезном ответе Артура Голдсмита выше: если вы перемещаете указатель мыши от одного элемента к другому в IE (по крайней мере до IE 9), у вас могут возникнуть некоторые проблемы, чтобы заставить его работать правильно, если новый элемент имеет прозрачный фон (который будет по умолчанию). Мой обходной путь - дать новому элементу прозрачное фоновое изображение.
Для таких, как я, которым нужен был ответ, который не зависел бы от событий наведения/входа/выхода браузера или состояний наведения. У меня была ситуация в слайдере на главной странице, левая и правая области щелчка слайда могли перекрывать (а иногда и полностью закрывать) кнопки CTA в баннере - это делает все предыдущие методы бесполезными (браузер сообщает только о событиях для элемента с наивысший z-индекс). Мне было поручено сделать так, чтобы событие щелчка больше заботилось о кнопке, чем о функциональности баннера, когда щелчок был по кнопке.
Мое полное решение выглядит так:
jQuery('.carousel-control-prev').on('click.testClick', function(e) {
var bannerButtons = jQuery('.banner-content a');
for (var i = 0; i < bannerButtons.length; i++) {
if (isMouseOver(bannerButtons.eq(i), e)) {
e.preventDefault();
e.stopPropagation();
bannerButtons[i].click();
}
}
});
function isMouseOver($el, e) {
if ($el.is(':visible')) {
var offset = $el.offset();
var x = (e.pageX - offset.left);
var y = (e.pageY - offset.top);
if (x > 0 && x < $el.outerWidth() && y > 0 && y < $el.outerHeight()) {
return true;
}
}
return false;
}
Это, вероятно, можно было бы сделать с небольшой дополнительной работой и тестированием, но на данный момент это делает то, что мне нужно - в данном случае перехватывает щелчок левой кнопкой мыши по баннеру, проверяет, не находится ли мышь над кнопкой CTA, и если это так, щелкните CTA вместо навигации по баннеру.
Я прекрасно понимаю, что лучшим решением было бы изменить дизайн области баннера, чтобы этого не могло произойти вообще, но дизайн находится вне моего контроля.
Я объединил идеи из этой темы и придумал это, что полезно для показа / скрытия подменю:
$("#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.
Продолжая то, что сказал "Happytime harry", обязательно используйте функцию jquery.data () для хранения идентификатора тайм-аута. Это сделано для того, чтобы вы могли очень легко получить идентификатор тайм-аута, когда "mouseenter" будет запущен на том же элементе позже, что позволит вам устранить триггер для исчезновения всплывающей подсказки.
Вы можете использовать jQuery mouseenter и mouseleave. Вы можете установить флаг, когда мышь входит в нужную область, и отменить флаг, когда она покидает область.
Я не мог использовать ни одно из предложений выше.
Почему я предпочитаю свое решение?
Этот метод проверяет, находится ли мышь над элементом в любое время, выбранное Вами.
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");
}
});
Ты можешь использовать 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');
});
это то, о чем я говорил:)