移动端滚动时避免触发touchstart及点击事件适配问题咨询
解决移动端click+touchstart冲突及事件差异问题
嘿,我来帮你搞定这两个移动端交互的常见坑:
一、如何避免滚动时误触发事件?
你遇到的问题根源在于touchstart太“灵敏”——用户手指刚碰到元素就会触发,不管接下来是点击还是滚动。要区分这两种行为,我们可以通过记录触摸的起始位置,在触摸结束时判断是否有明显移动来决定是否执行逻辑:
let touchStartX, touchStartY; $('.class') .on('touchstart', function(e) { // 记下触摸刚开始的坐标 const touch = e.originalEvent.touches[0]; touchStartX = touch.clientX; touchStartY = touch.clientY; }) .on('touchend', function(e) { const touch = e.originalEvent.changedTouches[0]; const diffX = Math.abs(touch.clientX - touchStartX); const diffY = Math.abs(touch.clientY - touchStartY); // 设置一个阈值(比如5px),移动距离小于这个值才判定为点击 if (diffX < 5 && diffY < 5) { // 这里放你的点击处理逻辑 console.log('这是真正的点击,执行操作~'); } // 移动超过阈值?那就是滚动,啥也不做 }) .on('click', function(e) { // 阻止click的默认行为,避免touchend和click重复触发 e.preventDefault(); // 要是需要兼容非触摸设备,也可以把逻辑放这儿,但要注意去重 });
另一种更简单的思路是用touchmove标记是否在滚动:
let isScrolling = false; $('.class') .on('touchstart', function() { isScrolling = false; }) .on('touchmove', function() { // 只要手指动了,就标记为滚动状态 isScrolling = true; }) .on('touchend', function() { if (!isScrolling) { // 不是滚动,执行点击逻辑 } }) .on('click', function(e) { e.preventDefault(); });
这两种方法都能有效区分点击和滚动,解决误触发的问题。
二、为什么有的元素只需要click,有的必须加touchstart?
这个差异主要和浏览器对不同元素的原生处理有关:
原生可交互元素自带优化:像
<a>、<button>、<input>这类浏览器原生的可点击元素,现代移动端浏览器会自动把触摸事件转化为click事件,而且很多已经去掉了早年的300ms点击延迟(当时是为了判断用户是不是要双击缩放)。所以这类元素只绑click也能有不错的响应速度。自定义元素需要手动增强交互:而
<div>、<span>这类非原生交互元素,浏览器默认不会给它们做触摸优化。如果只绑click,在一些旧的移动端浏览器上会有300ms的延迟,用户点了之后要等一会儿才有反应,体验很差。加touchstart就能让元素在手指刚碰到的时候就响应,提升即时感。
另外还要注意,如果元素被设置了pointer-events: none,那不管绑什么事件都不会生效,得确保这个CSS属性是正常的。
内容的提问来源于stack exchange,提问作者Henrik Petterson
相关产品推荐
相关产品推荐

