移动端如何实现长按元素后才禁止页面滚动?
实现长按拖拽时禁止页面滚动,未长按则允许滚动的解决方案
需求说明
用户触摸并长按指定元素后可拖拽,拖拽期间禁止页面滚动;若未长按足够时间(1秒)就触发拖拽,页面保持正常滚动。
期望行为
- ✅ 长按1秒后拖拽,页面无滚动
- ✅ 未长按1秒,页面正常滚动
- ✅ 触摸非拖拽元素时,页面正常滚动
不期望行为
- ❌ 长按1秒后仍能滚动页面
- ❌ 未长按就拖拽时,页面滚动被禁止
当前问题与尝试方案
现有代码存在长按1秒后仍可滚动页面的问题,已尝试以下方案但未解决:
- 在
touchstart事件处理器中调用event.preventDefault():提前禁止页面滚动,不符合需求 - 存储
touchstart事件以便长按后调用event.preventDefault():无效 touchstart时临时禁用页面滚动,未长按则恢复:无法阻止下拉刷新等浏览器原生滚动特性,需要类似event.preventDefault()的有效方案
解决方案
核心思路是通过定时器判断是否触发长按,仅在长按生效后才在touchmove中阻止页面滚动,具体实现代码如下:
<div class="draggable">可长按拖拽的元素</div> <div>普通元素,触摸可正常滚动</div> <style> .draggable { width: 200px; height: 200px; background: #42b983; color: white; text-align: center; line-height: 200px; position: absolute; } body { height: 2000px; } </style> <script> const draggableEl = document.querySelector('.draggable'); let longPressTimer = null; let isDraggableEnabled = false; let startX, startY; // 触摸开始:启动长按定时器 draggableEl.addEventListener('touchstart', (e) => { startX = e.touches[0].clientX; startY = e.touches[0].clientY; longPressTimer = setTimeout(() => { isDraggableEnabled = true; }, 1000); }); // 触摸移动:仅长按生效后阻止滚动并执行拖拽 draggableEl.addEventListener('touchmove', (e) => { if (!isDraggableEnabled) return; e.preventDefault(); // 阻止页面滚动 // 更新拖拽元素位置 const dx = e.touches[0].clientX - startX; const dy = e.touches[0].clientY - startY; draggableEl.style.left = `${parseInt(draggableEl.style.left || 0) + dx}px`; draggableEl.style.top = `${parseInt(draggableEl.style.top || 0) + dy}px`; startX = e.touches[0].clientX; startY = e.touches[0].clientY; }); // 触摸结束/取消:重置状态 ['touchend', 'touchcancel'].forEach(eventType => { draggableEl.addEventListener(eventType, () => { clearTimeout(longPressTimer); isDraggableEnabled = false; }); }); </script>
代码关键点说明
- 长按判断:通过
setTimeout设置1秒延迟,触发后标记拖拽状态为激活 - 滚动控制:仅在拖拽状态激活时,在
touchmove中调用e.preventDefault(),精准阻止页面滚动,避免提前禁用 - 状态重置:触摸结束或取消时清除定时器、重置拖拽状态,确保未长按的情况下页面滚动不受影响
- 元素区分:仅对指定的
.draggable元素绑定事件,触摸其他元素时页面保持正常滚动
内容的提问来源于stack exchange,提问作者Joshua F
相关产品推荐
相关产品推荐

