前端开发如何彻底禁止鼠标滚轮事件

1,523 阅读2分钟

在某些业务场景中,我们需要在页面某个部分禁用掉鼠标滚轮滚动事件。

通常处理这类事件的兼容,我们需要考虑IE模式标准模式。但是在鼠标滚轮滚动事件上,我们需要处理FireFox模式标准模式

除了火狐之外,所有的浏览器都可以使用MouseWheel事件来处理鼠标滚轮的响应。但是火狐却偏偏不支持MouseWheel,而使用无厘头的DOMMouseScroll,这玩意儿除了火狐以外其它浏览器都不兼容。

也就是说,对于鼠标滚轮事件的处理,火狐只能使用DOMMouseScroll。而非火狐则只能使用MouseWheel

这两种事件实现的原理不同,他们处理的数据也不同。

var firefox = navigator.userAgent.indexOf('Firefox') != -1;
firefox ? img.addEventListener('DOMMouseScroll', MouseWheel, false) : (img.onmousewheel = MouseWheel);

function MouseWheel(e) {
    e = e || window.event;
    if (e.stopPropagation) {
		e.stopPropagation();
	} else {
		e.cancelBubble = true;
	}
    if (e.preventDefault) {
		e.preventDefault();
	} else {
		e.returnValue = false;
	}
}

我们来看个完整例子的代码:

HTML部分

<style>
	span {font:14px/20px 微软雅黑;}
	#counter {
	 width:50px;height:20px;
	 border:1px solid #CCC;
	 background:#F9F9F9;
	 font:14px/20px Consolas;
	 text-align:center;
	 margin:10px;
	}
</style>

<span>使用鼠标滚轮调整数值大小</span><br/>
<div id="counter">0</div>

JavaScript部分

//判断浏览器
var isIE = navigator.userAgent.match(/MSIE (\d)/i);
isIE = isIE ? isIE[1] : undefined;
var isFF = /FireFox/i.test(navigator.userAgent);

//获取元素
var counter = document.getElementById("counter");

//鼠标滚轮事件
if (isIE < 9) {
  //传统浏览器使用MouseWheel事件
  counter.attachEvent("onmousewheel", function(event) {
    //计算鼠标滚轮滚动的距离
    //一格3行,每行40像素,所以除以120
    var v = event.wheelDelta / 120;
    counter.innerHTML = counter.innerHTML * 1 + v;
    //阻止浏览器默认方法
    return false;
  });
} else if (!isFF) {
  //除火狐外的现代浏览器也使用MouseWheel事件
  counter.addEventListener(
    "mousewheel",
    function(e) {
      //计算鼠标滚轮滚动的距离
      var v = e.wheelDelta / 120;
      counter.innerHTML = counter.innerHTML * 1 + v;
      //阻止浏览器默认方法
      e.preventDefault();
    },
    false
  );
} else {
  //奇葩的火狐使用DOMMouseScroll事件
  counter.addEventListener(
    "DOMMouseScroll",
    function(e) {
      //计算鼠标滚轮滚动的距离
      //一格是3行,但是要注意,这里和像素不同的是它是负值
      var v = -e.detail / 3;
      counter.innerHTML = counter.innerHTML * 1 + v;
      //阻止浏览器默认方法
      e.preventDefault();
    },
    false
  );
}

以上例子代码可以解决低版本浏览器的兼容,但是现在已经是2022年了。

标准化的滚轮事件 wheel早已被广大的现代浏览器所支持。而mousewheelDOMMouseScroll也被标记为非标准。

下面代码是MDN给的一个兼容所有浏览器的的监听鼠标滚动事件的方法。在项目中引用该文件,会在全局注册一个自定义的window.addWheelListener事件,事件内部实现了兼容。

(function(window, document) {
  var prefix = "",
    _addEventListener,
    onwheel,
    support;

  if (window.addEventListener) {
    _addEventListener = "addEventListener";
  } else {
    _addEventListener = "attachEvent";
    prefix = "on";
  }

  support =
    "onwheel" in document.createElement("div")
      ? "wheel" // 各个厂商的高版本浏览器都支持"wheel"
      : document.onmousewheel !== undefined
      ? "mousewheel" // Webkit 和 IE一定支持"mousewheel"
      : "DOMMouseScroll"; // 低版本firefox

  window.addWheelListener = function(elem, callback, useCapture) {
    if (support == "DOMMouseScroll") {
      _addWheelListener(elem, "MozMousePixelScroll", callback, useCapture);
    } else {
      _addWheelListener(elem, support, callback, useCapture);
    }
  };

  function _addWheelListener(elem, eventName, callback, useCapture) {
    elem[_addEventListener](
      prefix + eventName,
      support == "wheel"
        ? callback
        : function(originalEvent) {
            !originalEvent && (originalEvent = window.event);

            var event = {
              originalEvent: originalEvent,
              target: originalEvent.target || originalEvent.srcElement,
              type: "wheel",
              deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1,
              deltaX: 0,
              deltaZ: 0,
              preventDefault: function() {
                originalEvent.preventDefault
                  ? originalEvent.preventDefault()
                  : (originalEvent.returnValue = false);
              },
            };

            if (support == "mousewheel") {
              event.deltaY = (-1 / 40) * originalEvent.wheelDelta;
              originalEvent.wheelDeltaX &&
                (event.deltaX = (-1 / 40) * originalEvent.wheelDeltaX);
            } else {
              event.deltaY = originalEvent.detail;
            }

            return callback(event);
          },
      useCapture || false
    );
  }
})(window, document);