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

时间:2011-12-27 10:42:16

标签: javascript jquery javascript-events click mouseup

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

有办法做到这一点吗?


这不起作用:

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

15 个答案:

答案 0 :(得分:17)

使用事件捕获阶段

在要取消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
}
<button>Test capture click event</button>

JSFiddle Demo

会发生什么:

在触发button上的点击事件之前,周围div上的点击事件会被触发,因为它会在捕获阶段而不是冒泡阶段注册自己。

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

捕捉与冒泡:

从DOM根到叶子调用捕获阶段,而冒泡阶段来自根叶上的叶子(参见:wonderful explanation of event order)。

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

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


使用当前的事件API,您无法在已添加的另一个事件处理器之前添加新的事件处理程序。没有优先级参数和there's no safe cross-browser solution to modify the list of event listeners

答案 1 :(得分:10)

有一个解决方案!

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

on mousedown我为当前正在移动的元素添加了一个类,并在mouseup上删除了该类。

该课程所做的只是设置pointer-events:none

不知怎的,这使它工作,并且不会触发click事件。

答案 2 :(得分:5)

我有同样的问题,也没有找到解决方案。但我想出了一个似乎有用的黑客。

由于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);
  }
}

我希望这可以让您了解如何实现这一目标。正如我所说,这不是一个完整的解决方案,只是解释了这个概念。

答案 3 :(得分:4)

问题是有一个元素。它需要响应点击。它也需要被拖动。但是,当它被拖动时,它不需要在被删除时触发点击。

有点晚了,但也许它会帮助别人。创建一个名为“noclick”的全局变量,并将其设置为false。拖动项目时,将noclick设置为true。在你的点击处理程序中,如果noclick为true,则将其设置为false,然后使用preventDefault,return false,stopPropagation等。但这不适用于Chrome,因为Chrome已经具有所需的行为。如果浏览器不是Chrome,只需将其设置为只将noclick设置为true。

你的点击处理程序仍然会被触发,但至少它有办法知道它刚刚从拖动回来并且表现相应。

答案 4 :(得分:3)

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

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

el.addEventListener('click', (event) => {
  if (new Date() - clickTime < 150) {
    // do something
  }
})

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

答案 5 :(得分:1)

由于它们是不同的事件,您无法从onclick取消onmouseup,如果您致电preventDefaultcancelBubble,或等等,您正在停止onmouseup事件被进一步处理。 onclick事件仍然悬而未决,但可以说是被解雇了。

你需要的是你自己的布尔标志,例如isDragging。您可以在拖动开始时将此设置为true(例如,在onmousedown内或其他内容)。

但如果您直接从onmouseup重置为false,则在收到onclick事件(isDragging == false)后,您将不会再拖动,因为onmouseup会触发在onclick之前。

所以你需要做的是使用短暂的超时(例如setTimeout(function() {isDragging = false;}, 50);),所以当你的onclick事件被触发时,isDragging仍然是true,并且onclick。

答案 6 :(得分:0)

这可能是可能的,但我不确定你是否可以使用jQuery处理这种evt管理。 This code example不应该远离你的期望,或者至少给你一个方向。

function AddEvent(id, evt_type, ma_fonction, phase) {
    var oElt = document.getElementById(id);
    // modèle W3C mode bubbling
    if( oElt.addEventListener ) {
        oElt.addEventListener(evt_type, ma_fonction, phase);
    // modèle MSIE
    } else if( oElt.attachEvent ) {
        oElt.attachEvent('on'+evt_type, ma_fonction);
    }
    return false;
}

function DelEvent(id, evt_type, ma_fonction, phase) {
    var oElt = document.getElementById(id);
    // modèle W3C mode bubbling
    if( oElt.removeEventListener ) {
        oElt.removeEventListener(evt_type, ma_fonction, phase);
    // modèle MSIE
    } else if( oElt.detachEvent ) {
        oElt.detachEvent('on'+evt_type, ma_fonction);
    }
    return false;
}

    var mon_id = 'test';
    var le_type_evt = "mouseup";
    var flux_evt = false; // prevent bubbling
    var action_du_gestionnaire = function(e) {
        alert('evt mouseup on tag <div>');

        // 1ère méthode : DOM Lev 2
        // W3C
            if ( e.target )
                e.target.removeEventListener(le_type_evt, arguments.callee, flux_evt);
        // MSIE
            else if ( e.srcElement )
                e.srcElement.detachEvent('on'+le_type_evt, arguments.callee);

        // 2ème méthode DOM Lev2
        // DelEvent(mon_id, le_type_evt, action_du_gestionnaire, flux_evt);
    };


    AddEvent(mon_id, le_type_evt, action_du_gestionnaire, flux_evt);

答案 7 :(得分:0)

我最近遇到了同样的问题。这是我的解决方案:)

    initDrag: function (element) {
        var moved = false,
            target = null;

        function move(e) {
            // your move code
            moved = true;
        };

        function end(e) {
            var e = e || window.event,
                current_target = e.target || e.srcElement;

            document.onmousemove = null;
            document.onmouseup = null;

            // click happens only if mousedown and mouseup has same target
            if (moved && target === current_target) 
                element.onclick = click;

            moved = false;
        };

        function click(e) {
            var e = e || window.event;

            e.preventDefault();
            e.stopPropagation();

            // this event should work only once
            element.onclick = null;
        };

        function init(e) {
            var e = e || window.event;
            target = e.target || e.srcElement;

            e.preventDefault();

            document.onmousemove = move;
            document.onmouseup = end;
        };

        element.onmousedown = init;
    };

答案 8 :(得分:0)

这是我的拖放和点击相同元素的解决方案。

$('selector').on('mousedown',function(){
  setTimeout(function(ele){ele.data('drag',true)},100,$(this));
}).on('mouseup',function(){
  setTimeout(function(ele){ele.data('drag',false)},100,$(this));
}).on('click',function(){
  if($(this).data('drag')){return;}
  // put your code here
});

答案 9 :(得分:0)

我使用的解决方案如下:

var disable_click = false;

function click_function(event){
    if (!disable_click){
        // your code
    }
}

function mouse_down_function(event){
    disable_click = false; // will enable the click everytime you click
    // your code
}

function mouse_up_function(event){
    // your code
}

function mouse_drag_function(event){
    disable_click = true; // this will disable the click only when dragging after clicking
   // your code
}

根据名称将每个函数附加到相应的事件!

答案 10 :(得分:0)

我的解决方案不需要全局变量或超时,也不需要更改html元素,而只需要在纯js中具有一定等同性的jquery。

我声明了onClick函数

function onMouseClick(event){
     // do sth
}

我为MouseDown声明了一个函数(u在向上移动时也可能做同样的事情),以决定是否处理onclick事件

function onMouseDown(event){
     // some code to decide if I want a click to occur after mouseup or not
    if(myDecision){
        $('#domElement').on("click", onMouseClick);
    }
    else $('#domElement').off("click");
} 

快速说明:您应确保
 $('#domElement').on("click", onMouseClick);未执行多次。在我看来,如果是onMouseClick,它也会被多次调用。

答案 11 :(得分:0)

选项 #1:

可能最简单的解决方案是Event.stopImmediatePropagation()。虽然这伴随着一个警告,即同一元素上的所有其他点击事件侦听器在调用时将被取消,但在这种特定情况下它会起作用。

<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
  var a = 1;
});

$("#test").click (function (e) {
  // You should add a check here to only stop
  // if the element was actually moved
  e.stopImmediatePropagation();
});

$("#test").click (function (e) {
  var a = 2;
});

举个例子,看这个codepen:
https://codepen.io/guidobouman/pen/bGWeBmZ

选项 #2:

如果您拥有另一个点击处理程序,另一种(更安全)的解决方案是在事件默认操作被阻止时签入点击处理程序(您想要阻止的那个)。

<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
  var a = 1;
});

$("#test").click (function (e) {
  // You should add a check here to only prevent
  // if the element was actually moved
  e.preventDefault();
});

$("#test").click (function (e) {
  if(e.defaultPrevented) {
    return;
  }

  var a = 2;
});

答案 12 :(得分:-1)

$(document).mouseup(function(event){ // make sure to set the event parameter
    event.preventDefault(); // prevent default, like you said
});

需要注意的重要事项是event参数。

编辑:您想要取消拖动吗?

我知道这样做的方法是使用bind()(对于较旧的jQuery版本)或on()(对于jQuery 1.7+)来附加mousedown事件,然后使用unbind()off()分别将其分开。

$(document)
    .on("mousedown", function(){...})
    .on("mouseup", function(){
        $(document).off("mousedown");
    });

答案 13 :(得分:-1)

$(document).mouseup(function(event){

    event.preventDefault(); // this prevents only a default action but previously assigned listeners will be called
    event.stopImmediatePropagation() // if there are  others listeners which that shouldn't call 
}

答案 14 :(得分:-1)

如果您希望禁止click事件,则只在click事件处理程序中添加语句 event.preventDefault(),而不是mouseup事件处理程序。使用以下代码,您将使其正常工作。

<div id="test">test</div>
<script>
$("#test").mouseup (function (e) {
  var a = 1;

});
$("#test").click (function (e) {
 e.preventDefault();
  var a = 2;
});

希望这能解决你的问题。