Mouseenter без JQuery

Какой был бы лучший способ реализовать событие mouseenter/mouseleave как Javascript без jQuery? Какая лучшая стратегия для использования кросс-браузера? Я думаю, что какая-то проверка свойства event.relatedTarget/event.toElement в обработчиках событий mouseover/mouseout?

Как услышать ваши мысли.

Ответы

Ответ 1

(Полностью изменил мой страшный ответ. Повторите попытку.)

Предположим, что у вас есть следующие базовые методы кросс-браузера:

var addEvent = window.addEventListener ? function (elem, type, method) {
        elem.addEventListener(type, method, false);
    } : function (elem, type, method) {
        elem.attachEvent('on' + type, method);
    };

var removeEvent = window.removeEventListener ? function (elem, type, method) {
        elem.removeEventListener(type, method, false);
    } : function (elem, type, method) {
        elem.detachEvent('on' + type, method);
    };

(Довольно просто, я знаю.)

Всякий раз, когда вы реализуете mouseenter/mouseleave, вы просто присоединяете события к нормальные события mouseover/mouseout, но затем проверьте наличие двух важных данных:

  • Целевой объект - это правый элемент (или дочерний элемент правильного элемента)
  • Связанный с событиемTarget не является дочерним объектом цели

Поэтому нам также нужна функция, которая проверяет, является ли один элемент дочерним другой:

function contains(container, maybe) {
    return container.contains ? container.contains(maybe) :
        !!(container.compareDocumentPosition(maybe) & 16);
}

Последний "gotcha" - это то, как мы удаляем прослушиватель событий. Самый быстрый способ чтобы реализовать это, просто вернув новую функцию, которую мы добавляем.

Итак, у нас получилось что-то вроде этого:

function mouseEnterLeave(elem, type, method) {
    var mouseEnter = type === 'mouseenter',
        ie = mouseEnter ? 'fromElement' : 'toElement',
        method2 = function (e) {
            e = e || window.event;
            var target = e.target || e.srcElement,
                related = e.relatedTarget || e[ie];
            if ((elem === target || contains(elem, target)) &&
                !contains(elem, related)) {
                    method();
            }
        };
    type = mouseEnter ? 'mouseover' : 'mouseout';
    addEvent(elem, type, method2);
    return method2;
}

Добавление события mouseenter будет выглядеть следующим образом:

var div = document.getElementById('someID'),
    listener = function () {
        alert('do whatever');
    };

mouseEnterLeave(div, 'mouseenter', listener);

Чтобы удалить событие, вам нужно сделать что-то вроде этого:

var newListener = mouseEnterLeave(div, 'mouseenter', listener);

// removing...
removeEvent(div, 'mouseover', newListener);

Это вряд ли идеально, но все, что осталось, - это просто детали реализации. Важной частью было предложение if: mouseenter/mouseleave - это просто mouseover/mouseout, но проверяя, настроен ли вы на правильный элемент, и если связанная цель - это ребенок цели.

Ответ 2

Лучший способ, imho, - создать собственную систему событий.

Дин Эдвардс написал несколько лет назад, что я взял сигналы из прошлого. Его решение действительно работает из коробки.

http://dean.edwards.name/weblog/2005/10/add-event/

Ответ 3

Джон Ресг представил свою статью в конкурс , в котором его считали лучшим (примечание: Дин Эдвардс был одним из жюри). Итак, я бы сказал, проверьте это тоже.

Также его не помешает проходить через jQuery, DOJO источник раз в то время, чтобы увидеть лучшие методы, которые они используют, чтобы заставить работать кросс-браузер.

Ответ 4

другой вариант заключается в том, чтобы отличать истинные события mouseout от фальшивых (сгенерированных детьми) событий, используя hit-testing. Например:

elt['onmouseout']=function(evt){
  if (!mouse_inside_bounding_box(evt,elt)) console.debug('synthetic mouseleave');
}

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