26

我试图回答自定义下拉菜单的问题,但受到 Chrome 和 Firefox 中不一致行为的挑战。

演示: http: //jsfiddle.net/fyeht/ [添加滚动事件更清晰]

见下图,列表项可以使用箭头键导航。

重现问题:

  1. 在 Chrome 中打开控制台 ( F12)
  2. 单击列表中的一个项目(您会注意到控制台中记录了一些事件)
  3. 使用向下箭头键导航到列表中的下一项
  4. 最后,当您到达视图中的最后一个项目并且按下向下箭头会滚动时,会注意到该问题。查看日志以查看“滚动”、“鼠标输入”和“鼠标移动”[查看新演示]

问题是在到达视图项目的末尾后,它会滚动。即使鼠标没有被触动,它也会在 Chrome 中触发mouseentermousemove事件。在 FF 中,在滚动时它只会触发mouseenter有意义的。

在此处输入图像描述

问题):

  • 为什么mousemove鼠标未触动时触发?
  • 这只是浏览器不一致吗?找不到有关滚动时触发的事件的文档?(从来不知道有)

提交了错误报告:https ://code.google.com/p/chromium/issues/detail?id=241476

4

4 回答 4

10

在您的示例中,我看到 Chrome 和 FF都会在鼠标悬停在 上时触发mouseenter<ul> DOM 事件,并且按下键会触发浏览器滚动以将所选内容<li>显示在视图中。

但是,只有 Chrome 会另外触发mousemove事件。两者抛出的mouseenter事件对象中已经存在的一个明显区别是对于 Chrome,MouseEvent.offsetX并且MouseEvent.offsetY包含值,而在 FF 中,这些属性是undefined. 因此,当触发该输入时,Chrome 已经确定鼠标“已移动”。

由于MouseEvent.screenXMouseEvent.screenY事件上下文值在滚动触发的实例之间不会改变MouseEvent,因此可以通过存储来自先前事件的这些值来区分“人工” mouseenter / mousemove事件和“真实”事件。

DOM 事件规范

mousemove的DOM Level 2 事件规范如下:

当指针设备在元素上方移动时,会发生 mousemove 事件。

3级规范(工作草案)基本相同:

当指针设备在元素上方移动时,用户代理必须调度此事件。

似乎可以归结为一个人是否相对地解释“被移动”。

此外,在Level 3 spec on mouse event order 的部分中,它指出当指针移入元素时,它会按顺序触发mouseovermouseentermousemove。那里指定的每个案例总是将这三个放在一起,因此也许有人可能会解释为,如果要触发mouseenter事件,则还应该触发与输入元素相对应的mousemove事件。

于 2013-05-16T01:37:48.697 回答
1

这不是错误。mousemove 相对于事件附加到的元素。在您的情况下,您会看到鼠标没有移动,因为您将浏览器窗口作为参考。但是对于该滚动列表,每当滚动列表时,指向列表中某个元素的鼠标移动到不同的元素

想象你作为地球,一杯咖啡作为鼠标静止在桌子上,可滚动列表作为太阳:如果你(窗口)不动,那杯咖啡(鼠标)的位置在同一个地方;但是对于太阳(列表),它将看到地球和咖啡杯都在移动。

于 2013-05-22T21:27:33.830 回答
1

我真的怀疑这里存在浏览器不一致。您应该创建一个打印出 x 和 y 坐标的 mousemove 事件。您可能会看到鼠标确实移动了一点。如果是这种情况,请尝试使用插件 hoverIntent 来消除此类问题。

编辑:

使用向上和向下箭头键,我现在可以复制该问题。是的,它确实看起来像某种错误!我敢打赌 mousemove 坐标增量很小。也许光标移动一两个像素?我想说,要克服这个问题,请向 mousemove 函数添加一个检查,该函数将先前 mousemove 的 xy 坐标与当前 mousemove 的 xy 坐标进行比较。确定它是否不仅仅是几个像素。如果是这样,你知道这是一个真正的鼠标移动。如果它更少,您可以将其归为 chrome 错误。

进一步编辑:

似乎您发现了一个错误,在 Chrome 中可能不应该触发 mousemove。如果你足够破解它,可能会有一些解决方法。但最好的解决方案可能只是避免在这种情况下使用 mousemove。一般来说,mousemove 是那些昂贵的事件之一,只有在你真正需要它时才应该使用它。

于 2013-05-16T01:24:52.163 回答
1

这是一个很好的演示。在 Chrome 中,元素的鼠标移动绝对是​​相对的。在 chrome 中,只有当鼠标指针位于滚动条上方时,我才能获得 keydown 和滚动事件。如果我使用滚轮滚动并将鼠标悬停在滚动条上,我也可以获得仅滚动事件。通过拖动滚动会导致“鼠标移动”和“鼠标悬停”事件,这并不奇怪。

浏览器不仅会大量产生鼠标移动和鼠标悬停事件,而且它们并不能很好地表明用户的意图。事实上,这些事件是有用的熵源。在某种程度上存在一些细微差异,这是在这些“微事件”单独有用的背景下。要与它们一起工作,您必须设计一种方法来过滤它们,以便您想要链接到更高级别的操作的用户意图。您选择的任何合理的方法来理解这些事件都可能会将这些移动 - 滚动事件检测为垃圾。这就是你的观点真正值得注意和震惊的地方。第一阶段是根据坐标的元素和值过滤掉事件。它可能有助于创建状态机模型。您可以注册和注册处理程序以响应其他事件。您已经确定了这种情况,如果关键元素具有滚动条,您希望更改响应状态或反应标准。如果一个元素或其父元素有一个垂直滚动条,则会抛出具有相对较高 X 值的鼠标移动。

如果在该上下文中通过鼠标移动触发鼠标悬停,您可能还想忽略鼠标悬停。即使您通过注册或注销处理程序来更改状态,一次处理每个微事件也开始变得不切实际。可以通过创建事件序列 fifo 缓冲区来提取更多信息。注册事件处理程序以将新事件添加到缓冲区。您可能还希望从此缓冲区中的计时器事件中收集信息以建立更多上下文。您可以创建一个在数组中保存 fifo 的对象。这就像一个队列,但不是从某种意义上说它是一个等待处理事件的地方。相反,您的程序正在等待计算缓冲区中的模式,并根据模式触发更高级别的事件,接受或拒绝不同类型的事件并扩展,收缩或保存缓冲区的内容。然后,您可以评估 x 和 y 变化的移动事件,还可以根据您演示的滚动鼠标悬停模式和鼠标移动事件创建条件。

于 2013-05-16T21:16:56.283 回答