Cancel click event in the mouseup event handler

前端 未结 14 2415
梦毁少年i
梦毁少年i 2020-12-09 14:53

Writing some drag&drop code, I\'d like to cancel the click events in my mouseup handler. I figured preventing default should do the trick, but the click event is still f

相关标签:
14条回答
  • 2020-12-09 15:18

    The problem is there's an element. It needs to respond to clicks. It also needs to be dragged. However, when it's dragged, it needs to not trigger click when it is dropped.

    A little late, but maybe it'll help someone else. Make a global variable named "noclick" or something and set it to false. When dragging the item, set noclick to true. In your click handler, if noclick is true, set it to false and then preventDefault, return false, stopPropagation, etc. This won't work on Chrome though since Chrome already has the desired behavior. Just make it so that the drag function only sets noclick to true if the browser isn't Chrome.

    Your click handler will still get fired, but at least it has a way to know that it just came back from drag and behave accordingly.

    0 讨论(0)
  • 2020-12-09 15:20

    i recently faced with the same problem. Here's my solution :)

        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;
        };
    
    0 讨论(0)
  • 2020-12-09 15:21

    This is my solution for drag and click on same element.

    $('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
    });
    
    0 讨论(0)
  • 2020-12-09 15:22

    As they are different events, you cannot cancel onclick from onmouseup, if you call preventDefault or cancelBubble, or whatever, you are stopping the onmouseup event from being processed any further. The onclick event is still pending, yet to be fired, so to speak.

    What you need is your own boolean flag, e.g. isDragging. You can set this to true when dragging starts (e.g. within onmousedown, or whatever).

    But if you reset this to false directly from onmouseup, you will not be dragging any more when you receive your onclick event (isDragging == false), because onmouseup fires before onclick does.

    So what you need to do is use a short timeout (e.g. setTimeout(function() {isDragging = false;}, 50);), so when your onclick event is fired, isDragging will still be true, and your onclick event handler can simply have if(isDragging) return false; before it does anything else.

    0 讨论(0)
  • 2020-12-09 15:23

    Use the event capture phase

    Put an element around the element you want to cancel the click event for, and add a capture event handler to it.

    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

    What happens:

    Before the click event on the button is triggered the click event on the surrounding div gets fired because it registered itself for the capture phase instead of the bubbling phase.

    The captureClick handler then stops the propagation of it's click event and prevents the click handler on the button to be called. Exactly what you wanted. It then removes itself for cleanup.

    Capturing vs. Bubbling:

    The capture phase is called from the DOM root up to the leafs while the bubbling phase is from the leafs up the root (see: wonderful explanation of event order).

    jQuery always adds events to the bubbling phase that's why we need to use pure JS here to add our capture event specifically to the capture phase.

    Keep in mind, that IE introduced the W3C's event capturing model with IE9 so this won't work with IE < 9.


    With the current Event API you can't add a new event handler to a DOM Element before another one that was already added. There's no priority parameter and there's no safe cross-browser solution to modify the list of event listeners.

    0 讨论(0)
  • 2020-12-09 15:25
    $(document).mouseup(function(event){ // make sure to set the event parameter
        event.preventDefault(); // prevent default, like you said
    });
    

    The important thing to note is the event parameter.

    EDIT: You want to cancel the drag?

    The way I know to do this is to either use bind() (for older jQuery versions) or on() (for jQuery 1.7+) to attach the mousedown event, then use unbind() or off() respectively to detach it.

    $(document)
        .on("mousedown", function(){...})
        .on("mouseup", function(){
            $(document).off("mousedown");
        });
    
    0 讨论(0)
提交回复
热议问题