最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - HTML5 Drag and Drop effectAllowed and dropEffect - Stack Overflow

programmeradmin3浏览0评论

The relationship between these two properties seems to have been the source of some confusion. Based on reading both the MDN site and MSDN I thought I had figured it out, but now I am not sure...

I figured that when an element is dragged, you can specify what is allowed to happen to it (i.e. it can be moved, copied, linked to - one of the effectAllowed constants). This is the effectAllowed property.

Different drop targets do different things, so when you drag over another element it can control which "effect" takes place on the drop, this is the dropEffect property. So I set up a simple example to test this theory out:

JSFiddle

$("[draggable='true']").on("dragstart", function(e) {
    var dt =  e.originalEvent.dataTransfer;
    dt.effectAllowed = "copyMove";
    dt.setData("text/plain", "Foo");
});

$("#dropZoneCopy").on("dragover", function(e) {
    var dt =  e.originalEvent.dataTransfer;
    dt.dropEffect = "copy";
    e.preventDefault();
});
    
$("#dropZoneMove").on("dragover", function(e) {
    var dt =  e.originalEvent.dataTransfer;
    dt.dropEffect = "move";
    e.preventDefault();
});

I have a box the user can drag - the effects allowed are copyMove. I have one box that sets dropEffect to copy, and once that sets dropEffect to move. What I expect is that when the user drags over the "copy box" the cursor will change to indicate a copy will happen, as I drag over the "move box" the cursor changes to indicate a move...

Only Chrome behaves as I would expect. Is this because the other browsers are wrong or because I don't understand the spec. properly ?

UPDATE Some more information from fiddling with this;

In both Firefox and Chrome, if you have a drag source which indicates the effectAllowed is copy and a drop zone that says dropEffect is move then you cannot drop on the drop zone even if you cancel the event. I thought that dropEffect would be useful to read ondrop to see what to do, but it isn't available on Chrome, the dropEffect does not appear on the drop handler, e.g. trying to read the dataTransfer.dropEffect will say that the dropEffect is none even though you set it on dragover. Setting the dropEffect as noted above does influence the way the cursor is displayed.

On Firefox, the dropEffect does come through on the dropzone after being set on dragover, but it does not influence the display of the mouse cursor. On Firefox on Windows pressing the Ctrl key does affect the display of the mouse, but does not affect the dropEffect property.

The spec shows that the source can listen for the dragend event to see what happened. It should look at the dropEffect within this event. Chrome, Mozilla and Safari work as you would hope here, the drop effect appears in the dragend event. In IE if the effect allowed is a simple value e.g. "copy" then any successful drop results in this value appearing as the dropEffect on dragend. If the effectAllowed was a compound value like copyMove and you tried to select "move" on dragover by setting the dropEffect, you're out of luck, that will come through as dropEffect = "none" at the source on dragend. You are stuck with one cursor & one dropEffect and that is the effectAllowed set on dragstart if that effect is a simple value. Interestingly the dropEffect it seems does come through when you drag into a native application from IE11 at least (and i assume earlier).

Other notes

On Safari on a Mac - effectAllowed cannot be set programatically, therefore any dropEffect that gets set is valid. When you press the cmd key the effectAllowed becomes "move" and when you press the alt key the effectAllowed becomes "copy". Thereafter it works as you would hope, if the dropEffect is not one of these effectAlloweds the drop is not allowed by the browser.

More Info I've been spending some spare time working on an HTML5 drag and drop library I wrote a bunch more about this and other issues in the docs for it, if you're interested please take a look at the project

The relationship between these two properties seems to have been the source of some confusion. Based on reading both the MDN site and MSDN I thought I had figured it out, but now I am not sure...

I figured that when an element is dragged, you can specify what is allowed to happen to it (i.e. it can be moved, copied, linked to - one of the effectAllowed constants). This is the effectAllowed property.

Different drop targets do different things, so when you drag over another element it can control which "effect" takes place on the drop, this is the dropEffect property. So I set up a simple example to test this theory out:

JSFiddle

$("[draggable='true']").on("dragstart", function(e) {
    var dt =  e.originalEvent.dataTransfer;
    dt.effectAllowed = "copyMove";
    dt.setData("text/plain", "Foo");
});

$("#dropZoneCopy").on("dragover", function(e) {
    var dt =  e.originalEvent.dataTransfer;
    dt.dropEffect = "copy";
    e.preventDefault();
});
    
$("#dropZoneMove").on("dragover", function(e) {
    var dt =  e.originalEvent.dataTransfer;
    dt.dropEffect = "move";
    e.preventDefault();
});

I have a box the user can drag - the effects allowed are copyMove. I have one box that sets dropEffect to copy, and once that sets dropEffect to move. What I expect is that when the user drags over the "copy box" the cursor will change to indicate a copy will happen, as I drag over the "move box" the cursor changes to indicate a move...

Only Chrome behaves as I would expect. Is this because the other browsers are wrong or because I don't understand the spec. properly ?

UPDATE Some more information from fiddling with this;

In both Firefox and Chrome, if you have a drag source which indicates the effectAllowed is copy and a drop zone that says dropEffect is move then you cannot drop on the drop zone even if you cancel the event. I thought that dropEffect would be useful to read ondrop to see what to do, but it isn't available on Chrome, the dropEffect does not appear on the drop handler, e.g. trying to read the dataTransfer.dropEffect will say that the dropEffect is none even though you set it on dragover. Setting the dropEffect as noted above does influence the way the cursor is displayed.

On Firefox, the dropEffect does come through on the dropzone after being set on dragover, but it does not influence the display of the mouse cursor. On Firefox on Windows pressing the Ctrl key does affect the display of the mouse, but does not affect the dropEffect property.

The spec shows that the source can listen for the dragend event to see what happened. It should look at the dropEffect within this event. Chrome, Mozilla and Safari work as you would hope here, the drop effect appears in the dragend event. In IE if the effect allowed is a simple value e.g. "copy" then any successful drop results in this value appearing as the dropEffect on dragend. If the effectAllowed was a compound value like copyMove and you tried to select "move" on dragover by setting the dropEffect, you're out of luck, that will come through as dropEffect = "none" at the source on dragend. You are stuck with one cursor & one dropEffect and that is the effectAllowed set on dragstart if that effect is a simple value. Interestingly the dropEffect it seems does come through when you drag into a native application from IE11 at least (and i assume earlier).

Other notes

On Safari on a Mac - effectAllowed cannot be set programatically, therefore any dropEffect that gets set is valid. When you press the cmd key the effectAllowed becomes "move" and when you press the alt key the effectAllowed becomes "copy". Thereafter it works as you would hope, if the dropEffect is not one of these effectAlloweds the drop is not allowed by the browser.

More Info I've been spending some spare time working on an HTML5 drag and drop library I wrote a bunch more about this and other issues in the docs for it, if you're interested please take a look at the project

Share Improve this question edited Jan 23 at 8:39 user5127 15911 bronze badges asked Dec 9, 2013 at 12:58 WoodyWoody 8,0022 gold badges23 silver badges25 bronze badges 2
  • 3 Your understanding of the spec is fine, the browser support is lacking. See the answers here for some alternatives: stackoverflow.com/q/24000954/2126792 – pschueller Commented Jun 11, 2014 at 23:10
  • The spec/implementation seems very disappointing. As far as I can tell dataTransfer.dropEffect is of no use in a 'drop' event... – mpr Commented Apr 13, 2023 at 22:12
Add a comment  | 

2 Answers 2

Reset to default 1

You set effectAllowed on the drag source (dragstart) to set what actions are allowed (like copy, move, or copyMove).

dropEffect gets set on the drop target (dragover) which sets what happens when you drop (like copy or move).

The catch here is that dropEffect has to match one of the effectAllowed values otherwise the drop won't work.

Your setup is fine.

You set effectAllowed to copyMove on the draggable.
The copy box sets dropEffect to copy.
The move box sets dropEffect to move.

You expect:
Dragging over the first box should show the copy cursor. Dragging over the second box should show the move cursor.

What happens:

  • Chrome: Works as you’d expect. The cursor changes based on the dropEffect.
  • Firefox: The dropEffect works (you can see it in the drop event) but the cursor doesn’t update visually.
  • Safari: You can’t programmatically set effectAllowed. Instead, it’s determined by modifier keys:
    • Alt: Copy
    • Cmd: Move
  • IE11:
    • If effectAllowed is simple (like copy), it works fine.
    • If it’s compound (like copyMove), dropEffect often gets ignored, and you’re left with dropEffect set to none.

So you can:

  • Stick to one allowed effect (copy or move) for better cross-browser consistency.
  • Use CSS or overlays to visually indicate what’s happening, since browsers don’t always update the cursor properly.
  • For Firefox you can tell users to hold the Ctrl key if they need the copy cursor as a fallback.

take a look at https://web.dev/drag-and-drop/

function handleDrop(e) {
  e.stopPropagation(); // Stops some browsers from redirecting.
  e.preventDefault();

  var files = e.dataTransfer.files;
  for (var i = 0, f; f = files[i]; i++) {
    // Read the File objects in this FileList.
  }
}
发布评论

评论列表(0)

  1. 暂无评论