比较 jQuery 中绑定 mouseleave 事件和 mouseenter 事件的方法
我想使用 jQuery 在鼠标进入 div 时触发一个事件,并在离开 div 时触发一个单独的事件。我知道有很多插件、代码示例等可以解决这个特定问题。我只是好奇哪种方式在性能和内存管理方面最有效。
例如,假设我们有这样的 HTML 代码:
<div class="mouse-trap"> 1 </div>
<div class="mouse-trap"> 2 </div>
...
<div class="mouse-trap"> n-1 </div>
<div class="mouse-trap"> n </div>
1.单独的事件
我们可以单独维护事件。此代码可读且易于使用。
$(".mouse-trap").bind('mouseenter', function() {
// mouse came in
});
$(".mouse-trap").bind('mouseleave', function() {
// mouse left
});
2.嵌套事件
不要总是保留“mouseleave”事件,而是只在必要时创建它,然后在完成后将其丢弃,因为每个 mouseenter 事件只会有一个 mouseleave 事件。
$(".mouse-trap").bind('mouseenter', function() {
// mouse came in
$(this).one('mouseleave', function() {
// mouse left
});
});
在第一种情况下,如果您有 n 个事件,这意味着 jQuery 必须不断监听 nx 2 事件。
在第二种情况下,假设 div 没有相互嵌套,您只会在任何给定点监听 n + 1 事件。
诚然,我不确定事件查找到底需要多少时间,但我怀疑从浏览器到浏览器、从计算机到计算机,情况都会有所不同。对于相对较小的 n 值,这可能永远不会成为问题。但是如果 n 真的很大怎么办?会有明显的差异吗?
现在,如果可以将 div 相互嵌套,情况会发生怎样的变化?
例如:
<div class="mouse-trap">
<div class="mouse-trap">
<div class="mouse-trap">
...
</div>
<div class="mouse-trap">
...
</div>
</div>
...
<div class="mouse-trap">
...
</div>
</div>
最坏的情况是 n 个 div 相互嵌套。
因为它们是嵌套的,所以我相信当您向内移动时,外部 div 不会调用“mouseleave”事件。在这种情况下,我相信这两种情况都必须跟踪 nx 2 事件,但仅限于将鼠标悬停在最内部的 div 上时。
现在这又带来了另一个问题:绑定和取消绑定事件需要多少开销。我想我不久前读到过 jQuery 将所有事件保留在队列中,尽管在研究这个问题时我无法找到确认这一点的具体文档。因此,根据所使用的数据结构,排队/出队可能有 O(1) 或 O(n)< /strong> 成本。有谁知道这个的具体情况吗?
在场景 1 中,您预先绑定所有内容,就不必再搞乱它了(除非新的 div.mouse-traps 动态添加到页面)。这是发生的nx 2 次绑定。
在场景 2 中,您只需预先绑定 n 个事件,但理论上您使用鼠标进入和离开某个区域的次数没有限制。这些为必要的无限绑定创造了可能性。但在同样的方面,鼠标(以及操作该鼠标的人)只能快速移动,因此这些绑定也都分散在更长的时间内。这可以最大限度地减少大量绑定的影响。
综上所述,我认为第二种情况可能更好,但我是否忽略了其他事情?还有其他方法比我列出的两种方法更好吗?
对于这篇文章的冗长,我深表歉意。我只是想确保我详细阐述了我当前的思维过程。我正在开发一些将有大量鼠标事件的东西,并希望确保我能很好地与人们的系统配合。
I want to trigger an event when my mouse enters a div, and a separate event when it leaves the div using jQuery. I know there are plenty of plugins, code samples, etc. that solve this particular problem. I'm just curious which way would be most efficient in terms of both performance and memory management.
So for instance, assume we have HTML code like this:
<div class="mouse-trap"> 1 </div>
<div class="mouse-trap"> 2 </div>
...
<div class="mouse-trap"> n-1 </div>
<div class="mouse-trap"> n </div>
1. Separate events
We can maintain the events separately. This code is readable, and easy to work with.
$(".mouse-trap").bind('mouseenter', function() {
// mouse came in
});
$(".mouse-trap").bind('mouseleave', function() {
// mouse left
});
2. Nested events
Instead of always keeping a "mouseleave" event around, only create it when it's necessary and then trash it when we're done, since there will only ever be one mouseleave event for each mouseenter event.
$(".mouse-trap").bind('mouseenter', function() {
// mouse came in
$(this).one('mouseleave', function() {
// mouse left
});
});
In the first scenario if you have n events, this means jQuery is constantly have to listen for n x 2 events.
In the second scenario, assuming the div's aren't nested inside each other, you're only listening for n + 1 events at any given point.
Admittedly I'm not sure exactly how much time is involved with event lookups, but I'd suspect from browser to browser, and computer to computer it would be different. For a relatively small value of n this would probably never be an issue. But what if n was really large? Would there be a noticeable difference?
Now, how do things change if you can have divs nested inside of each other?
For example:
<div class="mouse-trap">
<div class="mouse-trap">
<div class="mouse-trap">
...
</div>
<div class="mouse-trap">
...
</div>
</div>
...
<div class="mouse-trap">
...
</div>
</div>
The worst case scenario here would be n divs nested inside each other.
Because they are nested, I believe the "mouseleave" event won't get called on the outer divs as you move inwards. In this case I believe both scenarios would have to keep track of n x 2 events, but only when mousing over the inner-most div.
Now this brings up another question of how much overhead is required to bind and unbind events. I thought I read a while back that jQuery keeps all events in a queue, although I wasn't able to find specific documentation confirming that when researching this issue. So depending on the data structure used, the queuing/dequeuing probably has either a O(1) or O(n) cost. Does anybody know the specifics of this?
In scenario 1, you bind everything once up front and you don't have to mess with it anymore (barring new div.mouse-traps getting dynamically added to the page). That's n x 2 bindings that take place.
In scenario 2, you only bind n events up front, but there could theoretically be no limit to how many times you enter and leave an area with your mouse. These creates a possibility for infinite bindings necessary. But in the same respect, a mouse (and the human that operates that mouse) can only move so quickly, so these bindings are also all spread out over a greater period of time. This could minimize the effect of the numerous bindings.
All of that to say, I think the second scenario is probably better, but am I overlooking something else? Are there other ways of doing it that are better than the two that I listed?
I apologize for the lengthiness of this post. I just wanted to make sure I elaborated on my current thought process. I'm working on something that will have a large number of mouse events and want to make sure I play nicely with people's systems.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
将所有
.mouse-trap
包裹在div
中,仅在其上绑定一次事件并使用event.target
来处理它。附带说明 - 您应该对其进行分析并查看哪种解决方案最适合您。
Wrap all
.mouse-trap
indiv
, bind the events only once on that and useevent.target
to handle it.As a side note - you should profile it and see which solution it the best for you.
这样可能会更好:
所以 jQuery 将只监听 n 个事件
也许我们可以为 N 创建插件,其中 N 是嵌套树的数量,但它需要将所有元素的数据保存在某处,这将使事件本身变慢
may be better like this:
so jQuery will listen only n events
may be we can create plugin for N where N is number of nested trees, but it will need to keep data of all elements somewhere which will make events themself slower
尽管我并不真正了解这两种解决方案会对项目性能造成的影响,但我个人倾向于第一种途径,即单独的事件。
关于您的一些担忧:
正如 Timothy Jones 在评论中所说,您必须考虑您绑定的闭包中包含的范围可能会对内存产生很大的影响。正如文章所述,在回调中使用函数的参数可能会导致性能问题(直到现在我才知道,很高兴知道)。即使您在方法中没有完全这样做,您附加事件的方式也与此相差不远,随着开发的进展,您可能会陷入陷阱。举办两个单独的活动,您甚至不必担心这一点。
在嵌套元素场景中,正如我在评论中建议的那样,您可以采用
mouseover
和mouseout
方法。它应该处理“在仍处于父级中的情况下进入子级”,因为通过mouseover
输入子级将触发mouseout
最后,关于绑定的活动侦听器的数量,正如eicto建议的那样,解除当前事件的绑定,然后按照调用方式绑定相反的事件,理论上应该会减少附加事件的总数
正如我所说,这不是技术答案,但由于开发了类似的东西,我发现这种途径(单独的事件)最终最适合灵活性和清晰度。
Even though I don't really have all the knowledge about the toll those two solutions would take on the performance of the project, I would personally lean towards the first avenue, separate events.
And about some of your concerns :
As Timothy Jones said in a comment, you have to consider the scope included in the closures you're binding can have a great memory impact. As the article states, using the arguments of a function inside a callback can potentially cause performance problems (which I didn't know until now, good to know). Even though you are not exactly doing so in your approach, the way you attach your events is not very far from it and you could potentially fall into the trap as your development progresses. Having your two separate events, you won't even have to worry about that.
In the nested elements scenario, as I suggested in my comment, you could go for a
mouseover
andmouseout
approach instead. It should take care of the 'entering the child while still being in the parent' as entering a child withmouseover
will trigger amouseout
on the parent.Lastly, about the number of active listeners binded, as eicto suggested, unbinding the current and then binding the opposed event as they are called should, in theory, cut the number of total attached events in half.
As I said, this is no technical answer, but for having developed something similar, I found this avenue (separate events) to be best suited both for flexibility and clarity in the end.
像这样的 O(2) 解决方案怎么样:
HTML:
JS:
How about O(2) solution like this:
HTML:
JS:
也许这不是您正在寻找的答案,但是..
不要太担心性能/内存管理 - 对于当今的计算机来说,这个特定问题是一个微不足道的问题,甚至不值得在如此细粒度的级别上进行分析。我认为更重要的是代码的整洁和可维护性。因此,使用 hover() 函数保持其简单:
Perhaps this isn't the answer you're looking for, but..
Don't worry so much about performance/memory management - for today's computers this particular issue is such a trivial problem that it's not even worth analyzing at such a granular level. I think much more important is the cleanliness and maintainability of your code. So keep it simple with a hover() function: