overflow-x: auto 使用鼠标实现横向滚动,区分触摸板和鼠标滚动事件的方法

news/2025/2/22 6:28:30

假设一个 div 的滚动只设置了 overflow-x: auto 我们发现使用鼠标的滚轮是无法左右滚动的,但是使用笔记本电脑的触摸板,或者在移动设备上是可以滚动的。所以我们需要兼容一下鼠标的横向滚动功能。

我们可以监控 wheel 事件,然后根据位置来计算滚动的距离,不能使用 mousewheel 因为 mousewheel 事件在火狐浏览器并不支持,mousewheel 已经逐渐被 wheel 事件代替。

区分触摸板和鼠标滚轮

触摸板支持的横向滚动十分丝滑,如果不区分鼠标滚轮和触摸板,把所有的 wheel 事件都用新写的方法,那么使用触摸板滑动的时候体验很不好,容易左右抖动。这是因为触摸板的 wheel 事件触发的频率相对于鼠标滚轮高很多。所以我们要保留触摸板原生支持的横向滚动方法,然后重写一下鼠标触发的 wheel 事件。

下面是区分触摸板和鼠标 wheel 事件的方法。

 const checkIsTrackpad = e => {
    if (isSafari()) {
      return e.deltaMode === 0 && Math.floor(Math.abs(e.wheelDeltaY)) < 4
    }
    if (isFireFox()) {
      return (
        e.deltaMode === WheelEvent.DOM_DELTA_PIXEL ||
        (typeof e.MozInputSource !== 'undefined' && e.MozInputSource === 5)
      )
    }
    // 鼠标滚轮通常以 120 为步长
    return e.sourceCapabilities?.firesTouchEvents || (e.constructor.name === 'WheelEvent' && e.wheelDeltaY % 120 !== 0)
  }

所以一个 div 的横向滚动的方法如下:


const onMouseWheel = e => {
  // 触摸板滚动
  const checkIsTrackpad = e => {
    if (isSafari()) {
      return e.deltaMode === 0 && Math.floor(Math.abs(e.wheelDeltaY)) < 4
    }
    if (isFireFox()) {
      return (
        e.deltaMode === WheelEvent.DOM_DELTA_PIXEL ||
        (typeof e.MozInputSource !== 'undefined' && e.MozInputSource === 5)
      )
    }
    // 鼠标滚轮通常以 120 为步长
    return e.sourceCapabilities?.firesTouchEvents || (e.constructor.name === 'WheelEvent' && e.wheelDeltaY % 120 !== 0)
  }
  const isTrackPad = checkIsTrackpad(e)
  if (isTrackPad) {
    return
  }
  // 鼠标滚动
  e.preventDefault()
  const delta = e.deltaY || e.deltaX
  //  serviceScrollContentEle 是 设置为 overflow-x: auto 的 div
  serviceScrollContentEle.value.scrollLeft += delta * (e.shiftKey ? 3 : 2)
  if (!isScrolling) {
    isScrolling = true
    // 使用这个方法更好
    requestAnimationFrame(() => {
      isScrolling = false
    })
  }
}


http://www.niftyadmin.cn/n/5861793.html

相关文章

计算机专业知识【深入理解子网中的特殊地址:为何 192.168.0.1 和 192.168.0.255 不能随意分配】

在计算机网络的世界里&#xff0c;IP 地址是设备进行通信的关键标识。对于常见的子网&#xff0c;如 192.168.0.0/24&#xff0c;我们可能会疑惑为何某些地址不能分配给主机使用。接下来&#xff0c;我们就以 192.168.0.0/24 为例&#xff0c;详细解释为何 192.168.0.1 和 192.…

高级运维:1. 对比 LVS 负载均衡群集的 NAT 模式和 DR 模式,比较其各自的优势 。2. 基于 openEuler 构建 LVS-DR 群集。

1. LVS 负载均衡群集的 NAT 模式和 DR 模式的对比 特性NAT 模式DR 模式配置复杂度配置简单&#xff0c;适合初学者和小型网络环境配置相对复杂&#xff0c;需要配置虚拟 IP 和 ARP 抑制性能性能瓶颈可能出现在负载均衡器&#xff0c;不适合高流量场景高性能&#xff0c;响应速…

深入理解 Kafka 主题分区机制

在分布式消息系统中&#xff0c;Apache Kafka 的主题分区机制是其核心特性之一。它不仅提供了高吞吐量和可扩展性&#xff0c;还通过分区实现了消息的有序存储和高效消费。本文将通过详细的代码示例和分析&#xff0c;帮助读者深入理解 Kafka 的主题分区机制。 一、Kafka 分区的…

深入解析 Uniapp 的页面结构

一、引言 Uniapp 是一个使用 Vue.js 开发跨平台应用的前端框架&#xff0c;它能让开发者通过编写一套代码&#xff0c;发布到 iOS、Android、H5、小程序等多个平台。在 Uniapp 开发中&#xff0c;清晰理解页面结构是高效开发的基础&#xff0c;本文将深入剖析 Uniapp 的页面结…

OpenSSL crt key (生成一套用于TLS双向认证的证书密钥)

OpenSSL—— TLS证书 问&#xff1a;如何生成一套TLS证书、密钥呢&#xff1f; 生成一套 TLS 证书&#xff0c;包括 根 CA 证书、服务器证书、客户端证书&#xff0c;可以使用 openssl 命令来完成。完整的步骤如下&#xff0c;包括根 CA、服务器证书和客户端证书的生成。 &am…

Apache Flink架构深度解析:任务调度、算子数据同步与TaskSlot资源管理机制

Apache Flink是一个分布式流处理框架&#xff0c;其核心架构设计围绕有界与无界数据流的统一处理能力展开。以下从任务分配、算子数据同步、TaskManager与JobManager的TaskSlot机制三个维度展开详细分析&#xff1a; 一、任务分配机制 Flink的任务分配基于并行度&#xff08;P…

HTTP 常见状态码技术解析(应用层)

引言 HTTP 状态码是服务器对客户端请求的标准化响应标识&#xff0c;属于应用层协议的核心机制。其采用三位数字编码&#xff0c;首位数字定义状态类别&#xff0c;后两位细化具体场景。 状态码不仅是服务端行为的声明&#xff0c;更是客户端处理响应的关键依据。本文将从协议规…

策略模式Spring框架下开发实例

策略类Spring框架下开发实例 先列出策略模式下需要那些类: 策略接口 (Strategy)&#xff0c;定义所有策略类必须遵循的行为。 具体策略类&#xff08;如 ConcreteStrategyA、ConcreteStrategyB&#xff09;&#xff0c;实现不同的算法或行为。 上下文类 (Context)&#xff0c;…