使用jQuery实现长按确认按钮时mouseup事件不触发求助
解决jQuery长按按钮中mouseup事件无法触发的问题
我之前也碰到过一模一样的情况,问题根源主要在两个地方:
e.preventDefault()的滥用,同时作用于鼠标和触摸事件时,会打乱浏览器的事件传递链条- 当你在
mousedown事件里修改元素类名(进而改变样式)时,如果这些样式修改了元素的布局、尺寸或者交互状态,会导致mouseup触发时光标已经不在原元素范围内,自然无法触发绑定在元素上的mouseup事件
为什么两种场景差异这么大?
当你的mousedown处理函数只有console.log和e.preventDefault()时,元素没有任何视觉或结构变化,鼠标抬起时光标依然停在元素上,所以mouseup能正常触发。但一旦添加了addClass('-loading -progress'),如果这两个类包含修改元素尺寸、位置,或者设置pointer-events: none这类样式,就直接打断了事件触发的逻辑。
解决方案一:将mouseup绑定到document全局
把mouseup/touchend事件绑定到文档上,这样不管鼠标移动到哪里,抬起时都能捕获到事件,进而处理长按的取消逻辑:
let clickDuration; const self = $('.your-button'); const confirmDuration = 2000; // 假设你的长按触发时长是2秒 self.on('mousedown touchstart', function(e) { // 只在触摸事件中调用preventDefault,避免干扰鼠标事件的正常传递 if (e.type === 'touchstart') { e.preventDefault(); } self.addClass('-loading -progress'); clickDuration = setTimeout(function() { self.trigger('click').removeClass('-progress'); console.log('clicked for 2 seconds'); }, parseInt(confirmDuration)); console.log(e); }); // 绑定到document,确保鼠标抬起时总能触发 $(document).on('mouseup touchend', function() { self.removeClass('-loading -progress'); if (clickDuration) { clearTimeout(clickDuration); } console.log('mouseup/touchend triggered'); });
解决方案二:确保元素样式修改不改变点击区域
如果不想绑定到全局,可以调整CSS,用伪元素实现加载状态,让原元素的尺寸和点击区域完全保持不变:
.your-button { position: relative; overflow: hidden; /* 保留原有按钮样式 */ } .your-button.-loading::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(255,255,255,0.5); /* 这里可以添加加载动画,比如旋转圆圈 */ pointer-events: none; /* 确保伪元素不阻挡原元素的事件 */ } .your-button.-progress { /* 只修改不影响布局的样式,比如文字颜色、背景色 */ background-color: #eee; }
这样修改后,原元素的点击区域没有任何变化,mouseup事件依然能正常触发在元素上。
额外注意事项
- 记得在
mouseup中检查clickDuration是否存在,避免清除不存在的计时器导致报错 - 如果必须使用
e.preventDefault(),尽量只针对触摸事件,鼠标事件的preventDefault可能会阻止浏览器默认行为(比如文本选择),进而影响事件传递
内容的提问来源于stack exchange,提问作者Jon Code
相关产品推荐
相关产品推荐

