Выполнение действия при наведении курсора мыши на элемент (или его дочерние элементы) (и выходе из него)

StackOverflow https://stackoverflow.com/questions/1674539

Вопрос

Представьте, что у меня есть следующие элементы:

+------------------+
|                  |
|    +----------------+
|    |                |
|    |                |
|    +----------------+
|                  |
+------------------+

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

parent.addEventListener('mouseover', function(e) {
  // log mouse is over me
}, false);

Если я наведу курсор мыши непосредственно на родительский элемент снизу, я получу прямое событие, но из-за маршрутизации событий, если я наведу курсор мыши сбоку (сначала нажму на дочерний элемент), я также получу событие от дочернего элемента, когда оно всплывет.

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

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

var isOver = false;

parent.addEventListener('mouseover', function(e) {
  if (isOver) return;
  isOver = true;
  // log mouse is over me
}, false);

parent.addEventListener('mouseout', function(e) {
  if (e.relatedTarget == this || e.relatedTarget.isDescendantOf(this)) return;
  isOver = false;
  // log mouse is leaving me
}, false);

По сути, в коде есть переменная состояния, позволяющая определить, "переопределила" ли мышь родительский элемент (либо через его дочерний элемент, либо нет), и если событие срабатывает снова, пока "переопределено", эти события игнорируются..мы также фиксируем событие выхода мыши и задаем его..является ли relatedTarget (цель, которую вы собираетесь ввести) МНОЙ?(родитель) или возможный ребенок от МЕНЯ?если это так, то ничего не предпринимайте..в противном случае установите для состояния "переполнено" значение false.

Итак, этот код действительно работает, но представьте, что я не могу использовать свойство relatedTarget для определения следующей цели, как бы вы поступили с этим поведением?

Я надеюсь, что это имеет смысл, у меня такое чувство, что в событиях недостаточно контекста, чтобы сделать это без relatedTarget, но я почувствовал, что вполне может быть точка зрения относительно изменения поведения свойства eventPhase (чтобы определить, является ли событие прямым или с пузырьками).

Также я не ищу ответов, говорящих "это не будет работать в ie, блядь-блядь"..Прямо сейчас я работаю только с браузерами w3c event spec.

Заранее спасибо, Стивен.


Редактировать, просто чтобы уточнить, я хочу, чтобы события происходили так, как если бы у меня был один элемент, который выглядел следующим образом (если элемент на самом деле был таким, как в приведенном выше примере):

+------------------+
|                  |
|                  +--+
|                     |
|                     |
|                  +--+
|                  |
+------------------+
Это было полезно?

Решение

Я думаю, что вам нужны IE "mouseenter" событие (срабатывает, когда пользователь перемещает указатель мыши внутри границ объекта) и "mouseleave" событие (срабатывает, когда пользователь перемещает указатель мыши за пределы объекта):

В отличие от onmouseover событие, посвященное onmouseenter событие не всплывает. Другими словами, onmouseenter событие не запускается, когда пользователь перемещает указатель мыши по элементам, содержащимся в объекте, тогда как onmouseover действительно стреляет.

То же самое для onmouseleave.

Вот пример: http://jsbin.com/uputi (добавить /edit к URL-адресу для редактирования исходного кода):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
<head> 
<title>Sandbox</title> 
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen"> 
#outer { width:200px; height:200px; border:1px solid #333; }
#inner { float:right; width:125px; height:80px; margin-right:-80px; border:1px solid #333; }
</style> 

<script> 
window.onload = function() {
  function mouseenter() {
    document.getElementById('dbg').innerHTML = 'mouse entered #outer boundary';
  }

  function mouseleave() {
    document.getElementById('dbg').innerHTML = 'mouse left #outer boundary';
  }

  var outer = document.getElementById('outer');

  if ('onmouseenter' in document.body) {
    // browser supports mouseenter/mouseleave natively (i.e., IE)
    outer.onmouseenter = mouseenter;
    outer.onmouseleave = mouseleave;
  }
  else {
    // simulate mouseenter/mouseleave in other browsers
    function wrap(fn) {
      return function(event) {
        var parent = event.relatedTarget;

        // Check if we're still within the same parent (traverse up parentNodes)
        while (parent && parent != this) {
          parent = parent.parentNode
        }

        if(parent != this) {
          // call the *real* mouseover/mouseout handler
          fn.call(this, event)
        }
      }
    }

    outer.onmouseover = wrap(mouseenter);
    outer.onmouseout = wrap(mouseleave);
  }
}
</script> 
</head> 
<body> 
  <div id="outer"> 
    <div><code>#outer</code></div> 
    <div>&nbsp;</div> 
    <div>&nbsp;</div> 
    <div id="inner"><code>#inner</code></div> 
  </div> 
  <div id="dbg"></div> 
</body> 
</html>

Он использует relatedTarget как и вы (что, к вашему сведению, отлично работает в стандартных браузерах), но без государственного флага.Видишь эта статья более подробная информация об эмуляции приведена здесь.Вы можете видеть только одно mouseenter событие запускается при входе в #outer элемент, а также тот самый #inner элемент.Это эффект "границы", к которому вы стремитесь (я думаю).

Если у вас есть возможность включить jQuery в ваше приложение, jЗапрос переносит эти фантастические события в другие браузеры.(обратите внимание, что jQuery использует технику, описанную ею внутри, с некоторыми незначительными изменениями).

Прототип 1.6.1 также есть такие события имитированный.

Другие советы

Я думаю, вам просто нужно Прекращение распространения

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top