对比scroll事件和wheel事件

2,149 阅读3分钟

说起scrollwheel,第一反应就是滚动事件,那具体有啥差别呢?

官方传送门scroll wheel

主要从下面四点进行分析

  • 触发条件
  • 判断方向
  • 阻止滚轮事件冒泡
  • 应用场景

触发条件

  1. 滚轮滚动
  • 能触发scroll和wheel事件,wheel先触发,scroll后触发
  • 滚动条到达起始点或者终点之后,wheel依然滚动,而scroll不再触发
  1. 滚动条拖动
  • 只能触发scroll,不能触发wheel
  1. 自定义操作触发滚动
  • 通过键盘上的向上或者向下按钮(每次修改scrollTop的大小为40) 都可以触发scroll事件
  • 通过toTop或者toBottom函数,也能触发scroll
  • 如果设置容器的overflow为hidden(就是container2),再去修改容器的scrollTop,依然会触发scroll事件
  • 如果设置容器的overflow为hidden,再进行滚轮操作,会触发wheel事件,不会触发scroll事件

综上, scroll事件会在滚动容器(document或者元素)时触发,而wheel则是在滚动滚轮或者类似输入设备时(触摸板)触发

<body class="body">
    <div class="container1"></div>
    <div class="container2">
        <div class="content">11</div>
    </div>
    <div class="operator">
        <button onclick="toTop()">往上</button>
        <button onclick="toBotttom()">往下</button>
    </div>
</body>
body {
    display: flex;
    overflow: auto;
}

.container1 {
    width: 200px;
    height: 120%;
    background-color: green;
}

.container2 {
    margin-left: 100px;
    width: 200px;
    height: 300px;
    background-color: yellowgreen;
    overflow: auto;
}

.content {
    width: 70%;
    height: 2000px;
    background-color: darkred
}
const $body = document.getElementsByTagName('body')[0]
const $container1 = document.getElementsByClassName('container1')[0]
const $container2 = document.getElementsByClassName('container2')[0]

function toTop() {
    $container2.scrollTop -= 10
}
function toBotttom() {
    $container2.scrollTop += 10
}

判断方向

  • 可以通过wheel事件的deltaY来判断滚动方向,正数向下,负数向上
  • mdn的文档上推荐使用scroll事件前后的scrollTop的差值来判断方向,个人觉得一般如果是输入设备引起的滚动,都会触发wheel事件;而非输入设备引起的滚动,一般都是人为控制,自己可以掌握方向。
  • 而在想实现模拟滚动条的时候,一般容器都会设置overflow: hidden,而此时得通过监听wheel来实现模拟滚动,通过delta值来判断更合适

阻止滚动事件冒泡

  • 本身不存在滚动事件冒泡的说法,scroll和wheel事件触发时,都不会冒泡(就像focus和blur,细想一下就能明白)
  • 但是当滚动条达到某一个顶点时,再次通过触发wheel事件的方式,会让最近的可滚动父元素触发scroll事件
  • 而在此研究的便是防止子元素触发的wheel事件,影响到父元素,导致父元素发生scroll
  • 实现:可以通过在wheel事件上设置 preventDefault 和 stopPropagation来阻止子元素的影响父元素(必须两者都设置才能生效)
function wheelEvent(event) {
    event.preventDefault()
    event.stopPropagation()
}

function addEvent(dom) {
    dom.addEventListener('wheel', wheelEvent)
}

应用场景

  • 简单来说,scroll事件比较合适应用于有实际滚动条存在的场景;反之则使用wheel事件
  • 如:需要自己在滚动过程中实现元素的吸顶或者吸底,那就使用scroll事件
  • 如:因一些特殊原因,原生的滚动条不能满足业务场景,则只能自己模拟实现满足业务的滚动条,那就使用overflow: hidden + wheel事件