scrollwheel 都是滚动事件,有啥差别呢?

  • scroll:元素滚动时触发的事件
  • wheel:用户滚动鼠标滚轮或类似的输入设备时触发的事件

触发条件

滚轮滚动或触控板滑动

  • 能触发 scrollwheel 事件,wheel 先触发,scroll 后触发
  • 滚动条到达起始点或者终点之后,wheel 依然触发,而 scroll 不再触发

滚动条拖动

只能触发 scroll,不能触发 wheel

键盘按键

  • 向下或向上按键(每次修改 scrollTop 的大小为 40)
  • 空格或 Shift + 空格
  • PageDown 或 PageUp

都会触发 scroll 事件,而不会触发 wheel 事件

其他

  • 修改 scrollTopscrollLeft 等都会触发 scroll 事件,而不会触发 wheel 事件(即使容器的 overflow: hidden;
  • 容器的 overflow: hidden; 进行滚轮操作,会触发 wheel 事件,不会触发 scroll 事件

判断方向

  • 通过 wheel 事件的 deltaY 来判断滚动方向,正数向下,负数向上
  • 推荐使用 scroll 事件前后的 scrollTop 的差值来判断方向

阻止冒泡

本身不存在滚动事件冒泡的说法,scrollwheel 事件触发时,都不会冒泡(就像 focusblur

但是当滚动条达到某一个顶点时,再次通过触发 wheel 事件的方式,会让最近的可滚动父元素触发 scroll 事件

而在此研究的便是防止子元素触发的 wheel 事件,影响到父元素,导致父元素发生 scroll

实现:可以通过在 wheel 事件上设置 preventDefaultstopPropagation 来阻止子元素的影响父元素(必须两者都设置才能生效)

阻止滚动

不能通过在 scroll 监听器中使用 event.preventDefault() 来阻止滚动,因为它在滚动之后才触发

应该:

  • 阻止 wheel:防止鼠标滚动
  • 阻止 keydown:防止键盘的 PageDown、PageUp 等键
  • 隐藏滚动条:防止拖动滚动条

当然,最好的方法应该是设置 CSS 的 overflow: hidden

应用场景

简单来说,scroll 事件比较合适应用于有实际滚动条存在的场景;反之则使用 wheel 事件

如:需要自己在滚动过程中实现元素的吸顶或者吸底,那就使用 scroll 事件,虚拟列表

如:因一些特殊原因,原生的滚动条不能满足业务场景,则只能自己模拟实现满足业务的滚动条,那就使用 overflow: hidden + wheel 事件,平滑滚动

参考