在mouseup事件处理程序中取消单击事件

Yar*_*ron 29 javascript jquery click mouseup jquery-events

编写一些拖放代码,我想在我的mouseup处理程序中取消单击事件.我认为防止默认应该做的伎俩,但点击事件仍然被触发.

有没有办法做到这一点?


这不起作用:

<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
  var a = 1;
  e.preventDefault();
});
$("#test").click (function (e) {
  var a = 2;
});
Run Code Online (Sandbox Code Playgroud)

flu*_*flu 19

使用事件捕获阶段

在要取消click事件的元素周围放置一个元素,并为其添加捕获事件处理程序.

var btnElm = document.querySelector('button');

btnElm.addEventListener('mouseup', function(e){
    console.log('mouseup');
    
    window.addEventListener(
        'click',
        captureClick,
        true // <-- This registeres this listener for the capture
             //     phase instead of the bubbling phase!
    ); 
});

btnElm.addEventListener('click', function(e){
    console.log('click');
});

function captureClick(e) {
    e.stopPropagation(); // Stop the click from being propagated.
    console.log('click captured');
    window.removeEventListener('click', captureClick, true); // cleanup
}
Run Code Online (Sandbox Code Playgroud)
<button>Test capture click event</button>
Run Code Online (Sandbox Code Playgroud)

JSFiddle演示

怎么了:

button触发click事件之前,周围的click事件div被触发,因为它在捕获阶段而不是冒泡阶段注册了自己.

然后captureClick处理程序停止传播它的click事件并阻止click调用按钮上的处理程序.正是你想要的.然后它会自行删除以进行清理.

捕捉与冒泡:

从DOM根到叶子调用捕获阶段,而冒泡阶段从叶子向上调用(参见:事件顺序的精彩解释).

jQuery总是将事件添加到冒泡阶段,这就是为什么我们需要在这里使用纯JS来将捕获事件专门添加到捕获阶段.

请记住,IE使用IE9引入了W3C的事件捕获模型,因此这不适用于IE <9.


使用当前的Event API,您无法在已添加的另一个之前向DOM Element添加新的事件处理程序.没有优先级参数,也没有安全的跨浏览器解决方案来修改事件监听器列表.


FDI*_*DIM 13

有一个解决方案!

这种方法对我很有用(至少在chrome中):

mousedown我加个班,以当前正在移动的元素,在mouseup我删除类.

所有课程都是集合 pointer-events:none

不知何故,这使它工作,并没有触发点击事件.

  • 看起来不错,但在 Chrome 80 上不适合我;`pointer-events: none` 也取消了 `mouseup`... (2认同)

Fre*_*röm 6

我遇到了同样的问题,也没有找到解决方案。但是我想出了一个可行的方法。

由于onMouseUp处理函数似乎无法使用preventDefault或stopEvent或其他任何方式取消对链接的单击,因此我们需要使链接自行取消。这可以通过编写一个onclick属性来完成,该属性在拖动开始时向a-tag返回false,并在拖动结束时将其删除。

并且由于onDragEnd或onMouseUp处理程序是在浏览器解释点击之前运行的,因此我们需要进行一些检查,以检查拖动在何处结束以及单击了哪个链接等等。如果它在拖动的链接之外结束(我们拖动了链接,以使光标不再位于链接上),则在onDragEnd中删除onclick处理程序;但是,如果它在光标位于拖动链接上的位置处结束(将触发单击),则我们让onclick-handler删除自身。很复杂吧?

不是完整的代码,只是为了向您展示这个想法:

// event handler that runs when the drag is initiated
function onDragStart (args) {
  // get the dragged element
  // do some checking if it's a link etc
  // store it in global var or smth

  // write the onclick handler to link element
  linkElement.writeAttribute('onclick', 'removeClickHandler(this); return false;');
}

// run from the onclick handler in the a-tag when the onMouseUp occurs on the link
function removeClickHandler (element) {
  // remove click handler from self
  element.writeAttribute('onclick', null);
}

// event handler that runs when the drag ends
function onDragEnds (args) {
  // get the target element

  // check that it's not the a-tag which we're dragging,
  // since we want the onclick handler to take care of that case
  if (targetElement !== linkElement) {
    // remove the onclick handler
    linkElement.writeAttribute('onclick', null);
  }
}
Run Code Online (Sandbox Code Playgroud)

我希望这会让您对如何实现这一目标有所了解。就像我说的那样,这不是一个完整的解决方案,仅是解释这个概念。


Kim*_*m T 6

我的情况的最佳解决方案是:

let clickTime;

el.addEventListener('mousedown', (event) => {
  clickTime = new Date();
});

el.addEventListener('click', (event) => {
  if (new Date() - clickTime < 150) {
    // click
  } else {
    // pause
  }
});
Run Code Online (Sandbox Code Playgroud)

这给了用户 150 毫秒的释放时间,如果他们花费的时间超过 150 毫秒,则认为是暂停,而不是点击