我试图回答自定义下拉菜单的问题,但是Chrome和FF中的行为不一致会对此产生挑战。
DEMO: http://jsfiddle.net/fyeht/ [添加滚动事件以获得更清晰]
见下图,可以使用箭头键导航列表项。
重现问题:
问题是在到达视图中的项目结尾后,它会滚动。即使鼠标未受影响,它也会触发Chrome中的mouseenter
和mousemove
个事件。在FF中,在滚动时它会触发mouseenter
,这是有意义的。
问题(S):
mousemove
? 提交错误报告:https://code.google.com/p/chromium/issues/detail?id=241476
答案 0 :(得分:10)
在您的示例中,我看到Chrome和FF都会在鼠标悬停在<ul>
上方时触发 mouseenter DOM事件,按下键会触发浏览器滚动为了将选定的<li>
纳入视野。
但是,只有Chrome还会触发 mousemove 事件。 mouseenter 事件对象中已经存在一个显而易见的差异,即两次抛出是针对Chrome,MouseEvent.offsetX
和MouseEvent.offsetY
值,而在FF中,这些属性为{{1} }。因此,当触发该输入时,Chrome已经确定鼠标“已移动”。
由于undefined
和MouseEvent.screenX
事件上下文值在滚动触发的MouseEvent.screenY
个实例之间没有变化,因此可以区分“人工” mouseenter / mousemove 事件和“真实”事件,通过存储先前事件中的这些值。
DOM Level 2 Event Specification for mousemove读取:
当指针设备在元素上移动时,会发生mousemove事件。
Level 3 spec (working draft)基本相同:
当指针设备在元素上移动时,用户代理必须调度此事件。
似乎可以归结为一个人是否相对地解释“被移动”。
此外,在section of the Level 3 spec on mouse event order中,它指出当指针移动到元素中时,它会触发鼠标悬停, mouseenter 和 mousemove ,按此顺序。在那里指定的每个案例总是将这三个组合在一起,所以也许有人可能会解释它如果你要触发 mouseenter 事件,你也应该触发 mousemove 对应于输入元素的事件。
答案 1 :(得分:1)
我真的怀疑这里存在浏览器不一致的问题。您应该创建一个打印出x和y坐标的mousemove事件。您可能会看到鼠标确实移动了一点点。如果是这种情况,请尝试使用插件hoverIntent来消除此类问题。
编辑:
使用向上和向下箭头键,我现在能够复制问题。是的,它确实看起来像某种虫子!我敢打赌,鼠标移动坐标增量很小。也许光标移动一个或两个像素?我想说,要克服这一点,请在mousemove函数中添加一个检查,将以前的mousemove的x-y坐标与当前mousemove的x-y坐标进行比较。确定它是否超过几个像素。如果是这样,你知道这是一个真正的鼠标移动。如果它更少,你可以将它作为一个铬小虫粉化。
进一步编辑:
似乎你发现了一个bug,当它可能不应该在chrome中被激活时。可能有一些解决方法,你可以弄清楚,如果你足够破解它。但最好的解决办法可能就是避免在这种情况下使用mousemove。一般来说,mousemove是那些昂贵的事件之一,只有在你真正需要的时候才能使用它。
答案 2 :(得分:1)
这是一个很好的演示。 在Chrome中,元素的鼠标移动绝对是相对的。在chrome中,只有当鼠标指针位于滚动条上时,我才能获得keydown和scroll事件。如果我使用滚轮滚动并将鼠标悬停在滚动条上,我也可以获得仅滚动事件。通过拖动滚动导致“鼠标移动”和“鼠标悬停”事件并不是很奇怪。
鼠标移动和鼠标不仅仅是浏览器产生的大量事件,它们不是用户意图的良好指示。事实上,这些事件是一个有用的熵源。 在某种程度上存在一些微小的差异,这是在这些“微观事件”是多么有用的背景下。要使用它们,您必须设计一种方法来过滤它们,以便您想要链接到更高级别的操作。您选择理解这些事件的任何合理方法都可能会将这些移动滚动事件视为垃圾。这是你的观点真的值得注意并且惊愕失措的地方。 第一阶段是根据坐标的元素和值过滤掉事件。创建状态机模型可能会有所帮助。您可以注册并注册处理程序以响应其他事件。您已经确定了这种情况,如果关键元素有滚动条,您需要更改响应状态if或反应条件。如果一个元素或它的父元素有一个垂直滚动条,则抛出鼠标移动的X值相对较高。
如果在该上下文中使用鼠标移动触发鼠标悬停,您可能还想忽略鼠标悬停。即使您通过注册或取消注册处理程序来改变状态,一次处理每个微事件也开始变得不切实际。可以通过创建事件序列fifo缓冲区来提取更多信息。 注册事件处理程序以向缓冲区添加新事件。您可能还希望从此缓冲区中的计时器事件中收集信息以建立更多上下文。您可以创建一个将fifo保存在数组中的对象。这就像一个队列,但不是因为它是一个等待处理事件的地方。相反,您的程序正在等待计算缓冲区中的模式,并根据模式触发更高级别的事件,接受或拒绝不同类型的事件并扩展,收缩或保存缓冲区的内容。然后,您可以评估移动事件的x和y变化,并创建条件,给出滚动鼠标移动模式和您演示的鼠标移动事件。
答案 3 :(得分:1)
这不是错误。 mousemove是相对于事件附加到的元素。在您的情况下,您会看到鼠标没有移动,因为您将浏览器窗口作为参考。但对于滚动列表,无论何时滚动列表,指向列表中某个元素的鼠标都会移到不同的元素上
想象一下,你作为地球,一杯咖啡静止在桌子上作为鼠标,可滚动列表作为太阳:如果你(窗口)不动,那一杯咖啡的位置(鼠标)和你在同一个地方;但对于太阳(清单),它会看到地球和一杯咖啡都在移动。