Vue.js中如何让同一个方法在两个事件中仅触发一次?
解决触摸屏上touchstart和click事件重复触发的问题
我完全懂你的困扰——既要兼顾鼠标和触摸屏的点击交互,又得避免拖拽时误触发click,结果绑定了touchstart后又遇到了重复调用addPin的问题。这其实是因为触摸屏设备上,浏览器会在触摸事件序列结束后自动模拟一个click事件,所以两个事件都会被触发。下面给你几个不需要第三方库的原生解决方案:
方案1:阻止touchstart的默认行为(简单直接)
在touchstart的处理函数里调用event.preventDefault(),就能让浏览器停止触发后续的模拟click事件。不过要注意,这个操作会禁用该元素上的一些默认触摸行为(比如文本选择、滚动等),如果你的元素不需要这些功能,这个方法非常高效。
修改后的代码:
<div @touchstart="handleTouchStart('1')" @click="addPin('1')"> 1 </div>
对应的处理函数(以Vue为例,你可以根据自己的框架/原生JS调整):
function handleTouchStart(id, event) { addPin(id); // 阻止浏览器触发后续的模拟click事件 event.preventDefault(); }
方案2:用标志位过滤重复触发(更安全,不影响默认行为)
如果不想破坏默认触摸行为,可以设置一个标志位,标记是否已经通过触摸触发过操作,在click事件里判断是否需要执行。
具体步骤:
- 定义一个变量(比如
isTouchTriggered)记录触摸事件是否已触发。 - 在touchstart中设置标志位为
true,并调用addPin。 - 用
setTimeout在300ms后重置标志位(浏览器模拟click的延迟通常在这个区间),避免影响后续的鼠标点击。 - 在click事件中,如果标志位为
true,直接跳过执行。
代码示例:
<div @touchstart="handleTouchStart('1')" @click="handleClick('1')"> 1 </div>
处理函数:
let isTouchTriggered = false; function handleTouchStart(id) { isTouchTriggered = true; addPin(id); // 300ms后重置标志位,不影响后续鼠标操作 setTimeout(() => { isTouchTriggered = false; }, 300); } function handleClick(id) { // 如果是触摸触发的后续模拟click,直接跳过 if (isTouchTriggered) return; addPin(id); }
方案3:结合触摸位移判断,区分点击和拖拽(完美适配你的需求)
你提到click事件在轻微拖拽时不会触发,那我们可以在触摸事件里判断用户是否有拖拽行为——只有当触摸位移很小时才判定为点击,这样既解决了重复触发问题,又能过滤拖拽操作,完全匹配你的原始需求。
具体步骤:
- 在touchstart时记录触摸的起始坐标。
- 在touchend时计算触摸位移,如果位移小于5px(可根据需求调整),就判定为点击,调用addPin并阻止后续click。
- 鼠标操作依然用click事件,它本身就会自动过滤拖拽行为。
代码示例:
<div @touchstart="handleTouchStart('1')" @touchend="handleTouchEnd('1')" @click="addPin('1')" > 1 </div>
处理函数:
let startX, startY; function handleTouchStart(id, event) { // 记录触摸起始位置 const touch = event.touches[0]; startX = touch.clientX; startY = touch.clientY; } function handleTouchEnd(id, event) { const touch = event.changedTouches[0]; const endX = touch.clientX; const endY = touch.clientY; // 计算位移,判断是否为点击(位移小于5px) const deltaX = Math.abs(endX - startX); const deltaY = Math.abs(endY - startY); if (deltaX < 5 && deltaY < 5) { addPin(id); // 阻止后续的模拟click事件 event.preventDefault(); } }
这个方案是最贴合你需求的:触摸屏上只有无拖拽的点击才会触发,不会和click重复;鼠标操作正常使用click,拖拽时也不会误触发。
内容的提问来源于stack exchange,提问作者Liga




