Как отключить события mouseout, вызванные дочерними элементами?

107

Опишу проблему подробнее:

Я хочу показывать абсолютное позиционирование div при наведении курсора на элемент. С jQuery это действительно просто и прекрасно работает. Но когда указатель мыши проходит над одним из дочерних элементов, он запускает событие mouseout содержащего его div. Как сделать так, чтобы javascript не запускал событие mouseout содержащего элемента при наведении курсора на дочерний элемент.

Какой самый лучший и самый короткий способ сделать это с помощью jQuery?

Вот упрощенный пример, чтобы проиллюстрировать, что я имею в виду:

HTML:

<a>Hover Me</a>
<div>
  <input>Test</input>
  <select>
    <option>Option 1</option>
    <option>Option 2</option>
  </select>
</div>

Javascript / jQuery:

$('a').hover( function() { $(this).next().show() }
              function() { $(this).next().hide() } );
Сандер Верслуис
источник
1
Без jQuery версии этого вопроса
Зак Сосье

Ответы:

210

Вопрос немного устарел, но я столкнулся с этим на днях.

Самый простой способ сделать это с последними версиями JQuery является использование mouseenterи mouseleaveсобытия , а не mouseoverи mouseout.

Вы можете быстро проверить поведение с помощью:

$(".myClass").on( {
   'mouseenter':function() { console.log("enter"); },
   'mouseleave':function() { console.log("leave"); }
});
Bytebrite
источник
5
Помогла моя проблема, связанная с javascript, не связанная с jquery. Я использовал mouseenter / mouseout вместо mouseleave со своими слушателями событий!
Джо Э.
1
Для целей поиска это поведение событий мыши эквивалентно AS3 ROLL_OVERи ROLL_OUTв нем.
Джефф Уорд,
2
Избавило меня от головной боли. Странно, как при наведении курсора на дочерние элементы запускается родительское mouseoutсобытие, хотя на самом деле оно все еще находится внутри родительского элемента.
javiniar.leonard
18

Для простоты я бы просто немного реорганизовал html, чтобы поместить вновь отображаемый контент внутри элемента, к которому привязано событие mouseover:

<div id="hoverable">
  <a>Hover Me</a>
  <div style="display:none;">
    <input>Test</input>
    <select>
      <option>Option 1</option>
      <option>Option 2</option>
    </select>
  </div>
</div>

Тогда вы можете сделать что-то вроде этого:

$('#hoverable').hover( function() { $(this).find("div").show(); },
                       function() { $(this).find("div").hide(); } );

Примечание: я не рекомендую встроенный CSS, но это было сделано, чтобы упростить усвоение примера.

Райан МакГири
источник
Это действительно очень простое и понятное решение. Спасибо за напоминание. Но в моей конкретной ситуации, которая не совсем такая, как в вопросе, это не вариант. Спасибо хоть!
Сандер Верслэйс
Попробовав разные методы, описанные другими здесь, в SO, я вернулся к вашему методу и заставил его работать в моем случае. Ура! :-)
Сандер Верслэйс
11

Ага, ребята, используйте .mouseleaveвместо .mouseout:

$('div.sort-selector').mouseleave(function() {
    $(this).hide();
});

Или даже используйте его в сочетании с live:

$('div.sort-selector').live('mouseleave', function() {
    $(this).hide();
});
Лорд Найтон
источник
8

Вы ищете jQuery-эквивалент javascript для предотвращения всплытия событий.

Проверь это:

http://docs.jquery.com/Events/jQuery.Event#event.stopPropagation.28.29

В основном вам нужно перехватить событие в дочерних узлах DOM, и на этом остановить их распространение вверх по дереву DOM. Другой способ, хотя на самом деле он не предлагается (поскольку он может серьезно повредить существующим событиям на вашей странице), - это установить захват событий для определенного элемента на странице, и он будет получать все события. Это полезно для поведения DnD и тому подобного, но определенно не для вашего случая.

Юваль Адам
источник
это работает так, как должно, не знаю, почему вы не могли заставить его работать ... просто информация, ссылка на документы изменилась, новая ссылка - docs.jquery.com/Events/jQuery.Event#event.stopPropagation. 28,29
zappan
3

Я просто проверяю, находятся ли координаты мыши вне элемента в событии mouseout.

Это работает, но для такой простой вещи много кода :(

function mouseOut(e)
{
    var pos = GetMousePositionInElement(e, element);
    if (pos.x < 0 || pos.x >= element.size.X || pos.y < 0 || pos.y >= element.size.Y)
    {
        RealMouseOut();
    }
    else
    {
         //Hit a child-element
    }
}

Код урезан для читабельности, из коробки не работает.


источник
1

Я согласен с Райаном.

Ваша проблема в том, что «следующий» div не является «дочерним» для A. HTML или jQuery не могут знать, что ваш элемент «a» связан с дочерним div в DOM. Их упаковка и наведение указателя мыши на оболочку означает, что они связаны.

Обратите внимание, что его код не соответствует лучшим практикам. Не устанавливайте скрытый стиль встроенным в элементы; если у пользователя есть CSS, но нет javascript, элемент будет скрыт и не сможет отображаться. Лучше поместить это объявление в событие document.ready.

user37731
источник
Я полностью согласен с добавлением скрытия в событие document.ready. Встроенный CSS должен был просто передать полный рабочий пример самым простым способом. Я отредактирую свой ответ, чтобы прояснить это.
Райан МакГири,
1

Я решил эту проблему, добавив pointer-events: none;свои дочерние элементы css

Антуан
источник
Это действительно очень помогло при исправлении устаревшего кода, создающего собственные всплывающие окна с событиями mouseover и mouseleave
CM
0

Обычно я видел, как это обрабатывается с задержкой около 1/2 секунды между перемещением мыши от элемента HoverMe. При перемещении указателя мыши в элемент, на который наведен курсор, вам нужно установить некоторую переменную, которая сигнализирует о том, что вы наводите курсор на элемент, а затем, в основном, не позволяла скрывать зависшую часть, если эта переменная установлена. Затем вам нужно добавить аналогичную функцию скрытия OnMouseOut из зависшего элемента, чтобы он исчезал при удалении мыши. Извините, я не могу дать вам код или что-то более конкретное, но я надеюсь, что это укажет вам в правильном направлении.

Кибби
источник
Да, idd, я только что реализовал подобное решение. Это действительно распространенная проблема. Мне действительно любопытно, какие еще есть решения ... Спасибо за ответ!
Сандер Верслэйс
0

Это старый вопрос, но он никогда не устареет. Правильный ответ должен быть дан bytebrite .

Я только хотел бы указать на разницу между mouseover / mouseout и mouseenter / mouseleave. Вы можете прочитать отличное и полезное объяснение здесь (перейдите в самый низ страницы, чтобы увидеть рабочую демонстрацию). Когда вы используете mouseout, событие останавливается, когда мышь входит в другой элемент, даже если это дочерний элемент. С другой стороны, когда вы используете mouseleave, событие не запускается, когда указатель мыши наведен на дочерний элемент, и это поведение, которого OP хотел бы достичь.

Эренор Пас
источник