简体   繁体   中英

jQuery detect mousedown inside an element and then mouseup outside the element

I have something similar to a drawing canvas, and I capture it's state on mouseup for undo purposes. The canvas isn't full screen, so you can draw with a brush and release outside the canvas. Something like this:

$("#element").mousedown(function(){
  $(document).mouseup(function(){
    //do something
  }); 
});

But this doesn't work of course. A plain $(document).mouseup doesn't work either, because I have many other UI elements and it saves the state each time you click on a UI element.

Any ideas?

var isDown = false;

$("#element").mousedown(function(){
    isDown = true;
});

$(document).mouseup(function(){
    if(isDown){
        //do something
        isDown = false;
    }
}); 

For the sake of simplicity I put isDown in the global namespace. In production you would probably want to isolate the scope of that variable.

The above answers will not work when text is selected.

The fix is to stop text from being selected when the mouse is down, and re-enable it when it's back up:

in your CSS:

.noselect {
    /* Prevent text selection */
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -o-user-select: none;
    user-select: none;
}

Then your JS:

var myButtonDown=false;

$('.ff', ffrw).mousedown(function() {
    myButtonDown=true;
    $('body').addClass('noselect');
    //Your code here
});

$(document).mouseup(function() {
    if (myButtonDown) {
        myButtonDown = false;
        $('body').removeClass('noselect');
    }
})

Hopefully you find this little solution to be helpful. You can see it in action here: http://jsfiddle.net/neopreneur/PR2yE/

$(document).ready(function(){
    var startMouseDownElement = null;

    $('#element').mousedown(function(){
        // do whatever
        //...

        // set mousedown start element
        startMouseDownElement = $(this);
    });

    // handle bad mouseup
    // $('#container, #container *').mouseup would be more efficient in a busy DOM
    $('body *').mouseup(function(event){
        event.stopPropagation(); // stop bubbling
        if($(this).attr('id') != $(startMouseDownElement).attr('id')){
            //oops, bad mouseup
            alert('bad mouseup :(');  
        }
    });
});

A possible implementation of mike's and waitingforatrain's answers in GWT. In the html head manage mouse up events (javascript code):

   var mouseUpHook = false;
   $(document).mouseup(function() {
       if (mouseUpHook) {
           mouseUpHook(null);
           mouseUpHook = false;
       }
   });

Let your custom Widget class implement MouseDownHandler and MouseUpHandler, and add those lines in your constructor to receive mouse events (java code):

    addDomHandler(this, MouseDownEvent.getType());
    addDomHandler(this, MouseUpEvent.getType());

Finally, add those methods in your custom Widget class (java and javascript code):

@Override
public void onMouseUp (MouseUpEvent event) {
    removeMouseUpHook();

    // ... do something else
}

private native void hookMouseUp () /*-{
    $wnd.$('body').addClass('noselect');
    var myThis = this;
    $wnd.mouseUpHook = function () {
        myThis.@your.custom.widget.class.full.qualified.Name::onMouseUp(Lcom/google/gwt/event/dom/client/MouseUpEvent;)(null);
    };
}-*/;

private native void removeMouseUpHook () /*-{
    $wnd.$('body').removeClass('noselect');
}-*/;

@Override
public void onMouseDown (MouseDownEvent event) {
    hookMouseUp();

    // ... do something else

    event.preventDefault();
}

Last line is usefull to prevent image dragging. Infact, user-select: none is not sufficent.

If you've got a lot of clickable elements like I have, you're gonna want to create a global mouse catcher and set your mouseup code within the mousedowns of clicked element. Here's the code I used.

    var MouseCatcher=function()
    {
        this.init=function()
        {
            var mc = this; 
            $(document).bind({
                mouseup:function(e) 
                {
                    mc.mouseup();
                }
            });
        }
        this.mouseup=function()
        {
            return false;
        }
    }
    var mouseCatcher = new MouseCatcher();
    mouseCatcher.init();



    $('#clickableElement').bind({
        mousedown: function(e)
        {
            console.log('mousedown on element');

            mouseCatcher.mouseup=function()
            {
                console.log('mouseup called from MouseCatcher');
                this.mouseup = function(){return false;}
            }

        },
        mouseup:function(e)
        {
            //mouseup within element, no use here.
        }
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM