没有 JQuery 的 mouseenter

Posted

技术标签:

【中文标题】没有 JQuery 的 mouseenter【英文标题】:mouseenter without JQuery 【发布时间】:2011-09-02 02:39:27 【问题描述】:

在没有 jQuery 的情况下,在 javascript 中实现类似 mouseenter/mouseleave 事件的最佳方法是什么?跨浏览器使用的最佳策略是什么?我正在考虑对 mouseover/mouseout 事件处理程序中的 event.relatedTarget/event.toElement 属性进行某种检查?

想听听你的想法。

【问题讨论】:

【参考方案1】:

恕我直言,最好的方法是制作自己的事件系统。

Dean Edwards 几年前曾写过一篇文章,我从过去那里得到了启发。然而,他的解决方案确实是开箱即用的。

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

【讨论】:

【参考方案2】:

(彻底改变了我糟糕的答案。让我们再试一次。)

假设您有以下基本的跨浏览器事件方法:

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 事件,然后检查两个重要细节:

    事件的目标是右元素(或右元素的子元素) 事件的 relatedTarget 不是目标的子对象

所以我们还需要a function that checks whether one element is a child of another:

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

最后一个“陷阱”是我们如何移除事件监听器。最快的方法 实现它只需返回我们添加的新函数。

所以我们最终会得到这样的结果:

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,但检查你是否定位正确的元素,如果 相关目标是目标的子对象。

【讨论】:

不幸的是,这个脚本在单个 mouseenter 上触发了大约 40-50 次。如果您执行简单的mouseEnterLeave(ele, 'mouseenter', function() console.log('TEST'); );,您将在控制台中获得大约 40 次“测试”。 @OscarGodson 你能说得更具体点吗?我在一堆浏览器中尝试了一个非常简单的示例,但无法重现您的问题。 (虽然我确实发现了一个愚蠢的 IE 错误,我已将其纳入答案。) “一个检查一个元素是否是另一个元素的 child 的函数”。你的意思是后裔,对吧?【参考方案3】:

John Resig 将他的 entry 提交给 contest,其中他的被评为最佳(注:Dean Edwards 是评审团之一)。所以,我想说,也看看这个。

此外,偶尔通过 jQuery、DOJO 源来实际查看他们用来使其跨浏览器工作的最佳实践也没有什么坏处。

【讨论】:

其实我上面贴的解决方案是响应 Resig 提交的。他认为他不喜欢它工作方式的某些方面,所以他重新编码。因此,为什么爱德华兹的帖子要在一个月后发布。 :) 我更喜欢 Edwards 的解决方案(出于他指定的许多原因)......虽然我绝对是 Resig 和他的工作的粉丝。 感谢提及。 guid 的概念甚至连 jQuery 都采用了。【参考方案4】:

另一种选择是使用命中测试将真实的mouseout 事件与虚假(子生成)事件区分开来。像这样:

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

我在 chrome 上使用过类似的东西,但请注意,它似乎可以解决问题。一旦有了可靠的 mouseleave 事件,mouseenter 就变得微不足道了。

【讨论】:

以上是关于没有 JQuery 的 mouseenter的主要内容,如果未能解决你的问题,请参考以下文章

在没有 jquery 的情况下使用 jquery-terminal 模拟器小部件

jquery animate方法动画效果没有

ENOENT: node_modules\jquery\dist\jquery.min.js'没有这样的文件或目录

没有jQuery accordian的jQuery accordian

带有 JQuery 的 Grails 项目,没有插件

对 slideToggle() jQuery 没有影响