跨浏览器规范化鼠标滚轮速度

2022-08-30 02:32:06

对于另一个问题,我撰写了这个答案,包括此示例代码

在该代码中,我使用鼠标滚轮放大/缩小HTML5 Canvas。我发现了一些规范化Chrome和Firefox之间速度差异的代码。但是,Safari中的变焦处理速度比其中任何一个都要快得多。

这是我目前拥有的代码:

var handleScroll = function(e){
  var delta = e.wheelDelta ? e.wheelDelta/40 : e.detail ? -e.detail/3 : 0;
  if (delta) ...
  return e.preventDefault() && false;
};
canvas.addEventListener('DOMMouseScroll',handleScroll,false); // For Firefox
canvas.addEventListener('mousewheel',handleScroll,false);     // Everyone else

我可以使用什么代码来获取相同数量的鼠标滚轮在Chrome v10 / 11,Firefox v4,Safari v5,Opera v11和IE9上滚动的相同“delta”值?

这个问题是相关的,但没有很好的答案。

编辑:进一步调查显示,一个滚动事件“向上”是:

                  | evt.wheelDelta | evt.detail
------------------+----------------+------------
  Safari v5/Win7  |       120      |      0
  Safari v5/OS X  |       120      |      0
  Safari v7/OS X  |        12      |      0
 Chrome v11/Win7  |       120      |      0
 Chrome v37/Win7  |       120      |      0
 Chrome v11/OS X  |         3 (!)  |      0      (possibly wrong)
 Chrome v37/OS X  |       120      |      0
        IE9/Win7  |       120      |  undefined
  Opera v11/OS X  |        40      |     -1
  Opera v24/OS X  |       120      |      0
  Opera v11/Win7  |       120      |     -3
 Firefox v4/Win7  |    undefined   |     -3
 Firefox v4/OS X  |    undefined   |     -1
Firefox v30/OS X  |    undefined   |     -1

此外,在 OS X 上使用 MacBook 触控板即使在缓慢移动时也会产生不同的效果:

  • 在 Safari 和 Chrome 上,鼠标滚轮的值为 3 而不是 120。wheelDelta
  • 在 Firefox 上,通常有时是 ,但是当滚动非常缓慢时,根本没有事件处理程序触发detail21

所以问题是:

区分此行为的最佳方法是什么(理想情况下没有任何用户代理或操作系统嗅探)?


答案 1

编辑2014年9月

鉴于:

  • OS X上同一浏览器的不同版本在过去产生了不同的值,并且将来可能会这样做,并且
  • 在OS X上使用触控板会产生与使用鼠标滚轮非常相似的效果,但给出的事件却大不相同,但JS无法检测到设备的差异。

...我只能建议使用这个简单的,基于符号的计数代码:

var handleScroll = function(evt){
  if (!evt) evt = event;
  var direction = (evt.detail<0 || evt.wheelDelta>0) ? 1 : -1;
  // Use the value as you will
};
someEl.addEventListener('DOMMouseScroll',handleScroll,false); // for Firefox
someEl.addEventListener('mousewheel',    handleScroll,false); // for everyone else

以下是正确的原始尝试。

这是我第一次尝试使用脚本来规范化值。它在OS X上有两个缺陷:OS X上的Firefox将产生1/3的值,OS X上的Chrome将产生它们应该存在的1/40的值。

// Returns +1 for a single wheel roll 'up', -1 for a single roll 'down'
var wheelDistance = function(evt){
  if (!evt) evt = event;
  var w=evt.wheelDelta, d=evt.detail;
  if (d){
    if (w) return w/d/40*d>0?1:-1; // Opera
    else return -d/3;              // Firefox;         TODO: do not /3 for OS X
  } else return w/120;             // IE/Safari/Chrome TODO: /3 for Chrome OS X
};

您可以在此处在自己的浏览器上测试此代码:http://phrogz.net/JS/wheeldelta.html

欢迎提出在OS X上检测和改进Firefox和Chrome上的行为的建议。

编辑:@Tom的一个建议是简单地将每个事件调用计为单个移动,使用距离的符号进行调整。这在OS X上的平滑/加速滚动下不会产生很好的效果,也不会完美地处理鼠标滚轮移动非常快的情况(例如 是240),但这些很少发生。此代码现在是此答案顶部显示的推荐技术,原因如下所述。wheelDelta


答案 2

我们在Facebook的朋友为这个问题提出了一个很好的解决方案。

我已经在我正在使用React构建的数据表上进行了测试,它像黄油一样滚动!

此解决方案适用于各种浏览器,Windows / Mac,并且都使用触控板/鼠标。

// Reasonable defaults
var PIXEL_STEP  = 10;
var LINE_HEIGHT = 40;
var PAGE_HEIGHT = 800;

function normalizeWheel(/*object*/ event) /*object*/ {
  var sX = 0, sY = 0,       // spinX, spinY
      pX = 0, pY = 0;       // pixelX, pixelY

  // Legacy
  if ('detail'      in event) { sY = event.detail; }
  if ('wheelDelta'  in event) { sY = -event.wheelDelta / 120; }
  if ('wheelDeltaY' in event) { sY = -event.wheelDeltaY / 120; }
  if ('wheelDeltaX' in event) { sX = -event.wheelDeltaX / 120; }

  // side scrolling on FF with DOMMouseScroll
  if ( 'axis' in event && event.axis === event.HORIZONTAL_AXIS ) {
    sX = sY;
    sY = 0;
  }

  pX = sX * PIXEL_STEP;
  pY = sY * PIXEL_STEP;

  if ('deltaY' in event) { pY = event.deltaY; }
  if ('deltaX' in event) { pX = event.deltaX; }

  if ((pX || pY) && event.deltaMode) {
    if (event.deltaMode == 1) {          // delta in LINE units
      pX *= LINE_HEIGHT;
      pY *= LINE_HEIGHT;
    } else {                             // delta in PAGE units
      pX *= PAGE_HEIGHT;
      pY *= PAGE_HEIGHT;
    }
  }

  // Fall-back if spin cannot be determined
  if (pX && !sX) { sX = (pX < 1) ? -1 : 1; }
  if (pY && !sY) { sY = (pY < 1) ? -1 : 1; }

  return { spinX  : sX,
           spinY  : sY,
           pixelX : pX,
           pixelY : pY };
}

源代码可以在这里找到:https://github.com/facebook/fixed-data-table/blob/master/src/vendor_upstream/dom/normalizeWheel.js