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
相关产品推荐
相关产品推荐

