You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何通过事件委托实现长按事件(不使用setTimeout)

在React中不使用setTimeout,通过事件委托实现长按事件识别

核心思路

不用setTimeout的话,我们可以通过记录按下和抬起的时间戳差值来判断是否触发长按,同时利用事件委托在父组件上统一监听事件,无需给每个可长按元素单独绑定事件:

  • 监听父元素的mousedown(或移动端touchstart)事件,记录触发事件的目标元素和按下时的时间戳
  • 监听mouseup/mouseleave(或移动端touchend/touchcancel)事件,计算当前时间与按下时间的差值,若超过设定的长按阈值(比如500ms),则判定为长按
  • 通过元素的自定义data-*属性标记可长按元素,方便在事件回调中识别目标

实现代码示例

import { useRef } from 'react';

function LongPressContainer() {
  // 用useRef存储按下状态,避免组件重渲染丢失数据
  const pressTracker = useRef({
    targetElement: null,
    pressStartTime: null
  });

  // 自定义长按阈值,单位:毫秒
  const LONG_PRESS_THRESHOLD = 500;

  const handlePressStart = (e) => {
    // 只处理带有data-longpress标记的元素
    const target = e.target;
    if (target.hasAttribute('data-longpress')) {
      pressTracker.current.targetElement = target;
      // 用performance.now()获取高精度时间戳
      pressTracker.current.pressStartTime = performance.now();
    }
  };

  const handlePressEnd = (e) => {
    const { targetElement, pressStartTime } = pressTracker.current;
    // 如果没有有效按下记录,直接返回
    if (!targetElement || !pressStartTime) return;

    // 计算按下时长
    const pressDuration = performance.now() - pressStartTime;
    // 确认当前抬起/离开的元素是之前按下的元素,避免误触发
    if (e.target === targetElement && pressDuration >= LONG_PRESS_THRESHOLD) {
      // 获取元素绑定的自定义操作,执行对应逻辑
      const action = targetElement.dataset.longpressAction;
      console.log(`触发长按操作:${action}`);
      // 这里可以替换成你需要的业务逻辑,比如弹窗、删除等
    }

    // 重置状态,准备下一次监听
    pressTracker.current.targetElement = null;
    pressTracker.current.pressStartTime = null;
  };

  return (
    <div
      // 绑定PC端事件
      onMouseDown={handlePressStart}
      onMouseUp={handlePressEnd}
      onMouseLeave={handlePressEnd}
      // 绑定移动端事件,实现跨端兼容
      onTouchStart={handlePressStart}
      onTouchEnd={handlePressEnd}
      onTouchCancel={handlePressEnd}
      style={{ padding: '20px', border: '1px solid #e0e0e0' }}
    >
      <button data-longpress data-longpress-action="delete">删除条目</button>
      <div 
        data-longpress 
        data-longpress-action="edit" 
        style={{ margin: '10px 0', padding: '12px', background: '#f5f5f5', borderRadius: '4px' }}
      >
        可长按编辑的文本块
      </div>
      <span data-longpress data-longpress-action="share" style={{ marginLeft: '10px', cursor: 'pointer' }}>🔗 分享</span>
    </div>
  );
}

export default LongPressContainer;

关键细节说明

  • 使用useRef存储状态:避免组件重渲染时丢失按下的目标元素和时间戳,比useState更适合存储这类不需要触发重渲染的临时状态
  • 跨端兼容:同时绑定PC和移动端的触摸事件,适配不同设备
  • 误触发防护:通过e.target === targetElement判断,防止鼠标/手指移开目标元素后再抬起仍触发长按
  • 自定义扩展:通过data-longpress-action属性可以给不同元素绑定不同的长按逻辑,扩展性强

内容的提问来源于stack exchange,提问作者Rameshmariappan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 17:10:36