防止鼠标按下和松开后的点击事件

10

在jQuery中,是否可以防止在mousedown和mouseup事件刚刚触发后,再次执行同一元素上的单击(click)事件。

欢迎提供任何帮助或示例。


1
我不是很明白,但是mousedown后跟着mouseup就是一次点击,如果只想让点击生效一次,可以使用one()方法。 - adeneo
可能这会对您有所帮助:https://dev59.com/HGox5IYBdhLWcg3w8IxJ - kongaraju
5个回答

2

有一种笨拙的方法是在鼠标按下时禁用按钮,然后在短时间内(如100ms)后启用它。如果mouseup事件发生在此期间,将不会触发click事件。

$('#btn').on('click', function() {
  alert('clicked')
});
$('#btn').on('mousedown', function() {
  var btn = $(this);
  btn.attr('disabled', 'disabled');
  setTimeout(function() { btn.removeAttr('disabled'); }, 100);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<body>
<button id='btn'>Click me</button>
</body>


2

似乎还没有人以优雅的方式回答这个问题,所以我想分享我在NewbeDev (来源:https://newbedev.com/cancel-click-event-in-the-mouseup-event-handler)找到的解决方案。

答案是使用捕获阶段,在事件在您的元素上触发之前,所有父级都会在称为“捕获阶段”的过程中接收它。然后在此之后,事件将传递到您的元素,其后跟随其父级在称为“冒泡阶段”的过程中。

这里的解决方案就是在捕获阶段顶端取消事件,因此它永远不会进入您的元素进行冒泡阶段。

我的用例是滑块,因此我使用的代码类似于:

slider.addEventListener('mousedown', ev => {
    // we start sliding (details omitted)

    function captureClick(e) {
        // we cancel the event and stop it from going further.
        // preventDefault() on its own should be enough for most cases
        // Your handler can also check e.defaultPrevented to know if preventDefault() was called
        e.preventDefault();
        // e.stopPropagation();
    }

   window.addEventListener('click', captureClick, true);
   document.addEventListener('mouseup', e => {
       // cleanup - we wait an extra frame to remove our capture 
       //           in case the click event is delayed
       requestAnimationFrame(() => {
           window.removeEventListener('click', captureClick, true);
       });
   });
});

1
在Chrome和Internet Explorer中,如果在mousedown或mouseup时分离并重新附加元素,则会防止触发单击事件,但在Firefox中不会。在Internet Explorer中,这个技巧无法捕捉到双击(但在Chrome中可以)。
但我不会依赖这种奇怪的行为,谁知道它是否会在某些时候改变。此外,请注意,分离和重新附加还可能对分离的元素的子元素产生副作用(iframes重新加载,文件字段重置等)。

1
有一个解决方案:

const COORDS = {
  xDown: null,
  xUp: null
}

const handleOnMouseDown = e => {
  e.preventDefault()
  COORDS.xUp = null
  COORDS.xDown = e.clientX
}

const handleMouseUp = e => {
  e.preventDefault()
  COORDS.xUp = e.clientX
}

const handleOnClick = e => {
  if (COORDS.xDown !== COORDS.xUp) {
    e.preventDefault()
    console.log('drag')
  } else {
    console.log('click')
  }
}

const el = document.getElementById('test')

el.addEventListener('mousedown', handleOnMouseDown)
el.addEventListener('mouseup', handleMouseUp)
el.addEventListener('click', handleOnClick)
#test {
  padding: 20px;
  display: block; 
  background: #ccc
}
<a href="#" id="test">Link</a>


-3

是的,如果在mouseup处理程序中使用return false;,应该是可能的,因为onclick在mousedown和mouseup发生后触发。这在常规javascript中是可行的,所以它也应该适用于jquery事件处理程序。

编辑:

从事件处理程序返回一个布尔值实际上应该足以消耗事件。但是,由于这在浏览器之间非常不稳定,您应该使用函数手动取消事件冒泡:

event.stopPropagation();

其中,event 是您的事件处理程序接收的参数。


如果两个事件都在同一个元素上触发,这种方法可能会出现问题。你能告诉我你想要实现什么,然后我或许可以提供一个解决方法。 - chucktator
这是一个糟糕的答案 - 它是错误的。我也尝试过它,但它没有起作用。 - chowey
看看一年前的编辑!你试过event.stopPropagation()吗?另外:从事件处理程序返回false是JavaScript标准中定义的方法,即使不是所有浏览器供应商都遵守这个标准。不要因为所提出的解决方案中的一个没有为您工作而对答案进行投票。 - chucktator

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接