admin管理员组

文章数量:1295862

I have made something like a drag-and-drop element with JS.

function Draggable(elm) {
    this.d = elm;
    this.style.position = "absolute";
    elm.onselectstart = elm.ondragstart = function() { return false; }
    elm.addEventListener('mousedown', this._start.bindAsEventListener(this), false);
}
Draggable.prototype._start = function (event) {
    this.deltaX = event.clientX;
    this.deltaY = event.clientY;
    if (!this.dm) {
        this.dm = document.createElement("div");
        this.dm.setAttribute("class", "dragger");
        this.dm.onmousemove = this._move.bindAsEventListener(this);
        this.dm.onmouseup = this._stop.bindAsEventListener(this);
        this.dm.onselectstart = RetFalse;
        this.dm.ondragstart = RetFalse;
    }
    document.body.appendChild(this.dm);

    this.lastX = this.lastY = 0;
    this.ondragstart();
    return false;
}
Draggable.prototype._move = function (event) {
    var newx = (event.clientX - this.deltaX);
    var newy = (event.clientY - this.deltaY);
    if (newx < this.x0) newx = this.x0;
    if (newx > this.x1) newx = this.x1;
    if (newy < this.y0) newy = this.y0;
    if (newy > this.y1) newy = this.y1;
    this.d.style.left = newx + "px";
    this.d.style.top = newy + "px";
    if (window.getSelection) window.getSelection().removeAllRanges(); else document.selection.empty();
    return false;
}
Draggable.prototype._stop = function (event) {
    document.body.removeChild(this.dm);
    return false;
}

The "dragger" is transparent DIV that fills the whole page, to prevent the dragged target from losing capture when mouse moves too fast. (If I could capture the mouse, I would need it.)

.dragger {
    cursor:move;
    position:absolute;
    width:100%;height:100%;
    left:0px;top:0px;
    margin:0px;padding:0px;
    z-index:32767;
    background: transparent;
    user-select: none;
    -webkit-user-select: none;
    -moz-user-select: none;
}

However, if I:

  1. Press left mouse button on the draggable element
  2. Drag it outside the client area (outside the brower window)
  3. Release mouse button

The element will lose the capture, so that if I move the cursor back, without having receive a mouse-up event, the element follows the cursor everywhere. (until you click to make a mouse-up again.)

Just now, I saw it perfectly done on this website: (www.box) Even if you release mouse button outside the browser window, the blue selecting box can still resize when the cursor moves, and disappear when button is released.

But I cannot receive any mousemove or mouseup when cursor is outside.

What API can I use to capture the mouse?

As you can see, I'm using Chrome Browser. It is said that there's no API like HTMLElement.setCapture in non-IE browser.

This page uses jQuery, but what does jQuery use? What is the raw javascript Code to do that?

I have made something like a drag-and-drop element with JS.

function Draggable(elm) {
    this.d = elm;
    this.style.position = "absolute";
    elm.onselectstart = elm.ondragstart = function() { return false; }
    elm.addEventListener('mousedown', this._start.bindAsEventListener(this), false);
}
Draggable.prototype._start = function (event) {
    this.deltaX = event.clientX;
    this.deltaY = event.clientY;
    if (!this.dm) {
        this.dm = document.createElement("div");
        this.dm.setAttribute("class", "dragger");
        this.dm.onmousemove = this._move.bindAsEventListener(this);
        this.dm.onmouseup = this._stop.bindAsEventListener(this);
        this.dm.onselectstart = RetFalse;
        this.dm.ondragstart = RetFalse;
    }
    document.body.appendChild(this.dm);

    this.lastX = this.lastY = 0;
    this.ondragstart();
    return false;
}
Draggable.prototype._move = function (event) {
    var newx = (event.clientX - this.deltaX);
    var newy = (event.clientY - this.deltaY);
    if (newx < this.x0) newx = this.x0;
    if (newx > this.x1) newx = this.x1;
    if (newy < this.y0) newy = this.y0;
    if (newy > this.y1) newy = this.y1;
    this.d.style.left = newx + "px";
    this.d.style.top = newy + "px";
    if (window.getSelection) window.getSelection().removeAllRanges(); else document.selection.empty();
    return false;
}
Draggable.prototype._stop = function (event) {
    document.body.removeChild(this.dm);
    return false;
}

The "dragger" is transparent DIV that fills the whole page, to prevent the dragged target from losing capture when mouse moves too fast. (If I could capture the mouse, I would need it.)

.dragger {
    cursor:move;
    position:absolute;
    width:100%;height:100%;
    left:0px;top:0px;
    margin:0px;padding:0px;
    z-index:32767;
    background: transparent;
    user-select: none;
    -webkit-user-select: none;
    -moz-user-select: none;
}

However, if I:

  1. Press left mouse button on the draggable element
  2. Drag it outside the client area (outside the brower window)
  3. Release mouse button

The element will lose the capture, so that if I move the cursor back, without having receive a mouse-up event, the element follows the cursor everywhere. (until you click to make a mouse-up again.)

Just now, I saw it perfectly done on this website: (www.box) Even if you release mouse button outside the browser window, the blue selecting box can still resize when the cursor moves, and disappear when button is released.

But I cannot receive any mousemove or mouseup when cursor is outside.

What API can I use to capture the mouse?

As you can see, I'm using Chrome Browser. It is said that there's no API like HTMLElement.setCapture in non-IE browser.

This page uses jQuery, but what does jQuery use? What is the raw javascript Code to do that?

Share asked Sep 20, 2011 at 6:32 RnMssRnMss 3,8533 gold badges29 silver badges40 bronze badges 2
  • In pictire: what it's blue selection. How this selection is generated? It's generated by Chrome browser, or by code in www.box/files page? – Andrew D. Commented Sep 20, 2011 at 7:31
  • @Andrew D. : It is actually a <div> generated by JS in the page. – RnMss Commented Jul 4, 2013 at 3:38
Add a ment  | 

2 Answers 2

Reset to default 8

Instead of creating a big, transparent element (dm), bind your mouse events to window.

It gets mouse events everywhere on the page; during dragging you'll keep getting mousemove events even if the cursor goes outside the window, as well as a mouseup if you release the mouse button outside the window.

P.S. If you call .preventDefault() on the mousedown event, the browser won’t select any text and you won’t have to clear the selection on mousemove.

Although it is a little outdated (FF now supports setCapture), I found this article to be extraordinarily helpful. The basis of the fix goes something like this:

var dragTarget = element.setCapture ? element : document; // setCapture fix

I've set up this little example. The javascript is copied straight from a webpage I'm building for a client where it works perfect*. Unfortunately I haven't been able to find a fix for draggable content inside an iframe, so it will still appear broken in Chrome if viewed at jsFiddle, Codepen, etc. You'll have to trust me that it works (or try it out yourself). If anyone knows of a fix for this iframe issue, please share.

*in Chrome, Safari and FF, I haven't tested in Opera or IE yet

本文标签: javascriptMouse capture in nonIE browserStack Overflow