You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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事件里判断是否需要执行。

具体步骤:

  1. 定义一个变量(比如isTouchTriggered)记录触摸事件是否已触发。
  2. 在touchstart中设置标志位为true,并调用addPin。
  3. setTimeout在300ms后重置标志位(浏览器模拟click的延迟通常在这个区间),避免影响后续的鼠标点击。
  4. 在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事件在轻微拖拽时不会触发,那我们可以在触摸事件里判断用户是否有拖拽行为——只有当触摸位移很小时才判定为点击,这样既解决了重复触发问题,又能过滤拖拽操作,完全匹配你的原始需求。

具体步骤:

  1. 在touchstart时记录触摸的起始坐标。
  2. 在touchend时计算触摸位移,如果位移小于5px(可根据需求调整),就判定为点击,调用addPin并阻止后续click。
  3. 鼠标操作依然用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

火山引擎 最新活动