Javascript - Duplicate File

I am trying to create a file drag and drop handler (drag the file into the browser window that will be used to download).

For some reason, when I link the drag and drop listener / $("body") instead of $("div") in the body, events fire several times in a row, sometimes even without stopping (apparently a loop). What could be the reason for this?

Here's a shortened version of the code: http://jsfiddle.net/WxMwK/9/

 var over = false; $("body") .on("dragover", function(e){ e.preventDefault(); if (! over) { over = true; $("ul").append($("<li/>").text("dragover")); } }) .on("dragleave", function(e){ e.preventDefault(); if (over) { over = false; $("ul").append($("<li/>").text("dragleave")); } }) .on("drop", function(e){ e.preventDefault(); if (over) { over = false; $("ul").append($("<li/>").text("drop")); } }); 

To check: drag the file to the orange area, you will see that the event is triggered several times in a row.

+4
source share
4 answers

Anon is (mostly) correct. Simply put: when the mouse moves around the edge of an element inside your target, you get a dropenter for the element under the cursor and dropleave for the element that was under the cursor earlier. This happens for absolutely any descendant.

You cannot check the dragleave related dragleave , because if you move the mouse from the target to the child, you will get a dropenter for the child and then dropleave for the target! This is ridiculous, and I don’t understand how useful it is.

Here's a crappy jQuery-based solution that I came up with some time ago.

 var $drop_target = $(document.body); var within_enter = false; $drop_target.bind('dragenter', function(evt) { // Default behavior is to deny a drop, so this will allow it evt.preventDefault(); within_enter = true; setTimeout(function() { within_enter = false; }, 0); // This is the part that makes the drop area light up $(this).addClass('js-dropzone'); }); $drop_target.bind('dragover', function(evt) { // Same as above evt.preventDefault(); }); $drop_target.bind('dragleave', function(evt) { if (! within_enter) { // And this makes it un-light-up :) $(this).removeClass('js-dropzone'); } within_enter = false; }); // Handle the actual drop effect $drop_target.bind('drop', function(evt) { // Be sure to reset your state down here $(this).removeClass('js-dropzone'); within_enter = false; evt.preventDefault(); do_whatever(evt.originalEvent.dataTransfer.files); }); 

The trick is based on two facts:

  • When you move the mouse from grandchild to child, both dragenter and dragleave will be queued for the target element - in that order.
  • dragenter and dragleave are queued.

So here is what happens.

  • In the dragenter event dragenter I set some common variable to indicate that the drag movement is not finished yet.
  • I use setTimeout with a zero delay to immediately change this variable.
  • But! Since two events are in the queue at the same time, the browser will not start any scheduled functions until both events complete the solution. So the next thing that happens is the dragleave event dragleave .
  • If the dragleave sees that it was paired with the dragenter on the same target element, this means that the mouse must move from some descendant to another offspring. Otherwise, the mouse actually leaves the target element.
  • Then setTimeout finally resolves to zero seconds later, returning the variable before another event occurs.

I can’t come up with a simpler approach.

+12
source

You add a listener to BODY HTMLElement for dragover , dragleave and drop .

As you continue to drag the DIV, there is a dragleave arrow because the mouse is no longer dragged over BODY, but over DIV.

Secondly, since you do not stop the bubble event on the DIV (there is no listener), the drag that fires on the DIV is sent to BODY .

If I come back:

The mouse is inserted into the body (when dragging)

-> drag and drop (body)

The mouse introduces a div in the body

-> fire retention (BODY)

-> drag fire (from DIV) -> bubling event -> drag fire (BODY)

A similar problem exists with mouseover and mouseout , which is fixed using mouseenter and mouseleave .

Perhaps you can try the same code using the dragenter event dragenter . If it does not work, you can check if event.target BODY . This test may help to skip an unwanted drag event.

Good luck.

0
source
 var over = false; $("body") .on("dragover", function(e){ e.preventDefault(); if (! over) { over = true; $("ul").append($("<li/>").text("dragover")); } }) .on("dragleave", function(e){ e.preventDefault(); if (over) { over = false; $("ul").append($("<li/>").text("dragleave")); } }) .on("drop", function(e){ e.preventDefault(); if (over) { over = false; } }); 
0
source

Or you can just use stop(); to stop creating animations

0
source

All Articles