I want to overlay a div over the viewport when the user drags a file onto the window.
However, I'm having trouble with the event propagation. When I set the overlay to display: block
it appears to fire off a dragleave
event and then another dragenter
and then another dragleave
again, so it's always in a post-dragleave state. Of course I call e.stopPropagation()
and e.preventDefault()
on the event object, but it doesn't seem to make a difference.
The console.log()
output when you drag something over the window:
dragenter
dragenter
dragleave
dragenter
dragleave
The css. #overlay
is set to display: none
by default, but will show if body
has the dragenter
class:
body {
position: absolute;
height: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0;
padding: 0;
}
#overlay {
position: absolute;
height: auto;
width: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url(bg.png) repeat-x top right, url(bg.png) repeat-x bottom left, url(bg.png) repeat-y top right, url(bg.p
ng) repeat-y bottom left;
display: none;
}
body.dragenter #overlay {
display: block;
}
The JavaScript; add the 'dragenter' class on dragenter
and removes it on dragleave
:
$(document).on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
console.log('dragenter');
$(document.body).addClass('dragenter');
});
$(document).on('dragleave', function (e) {
e.stopPropagation();
e.preventDefault();
console.log('dragleave';
$(document.body).removeClass('dragenter');
});
The html:
<body>
<div id="overlay">...</div>
...
</body>
I want to overlay a div over the viewport when the user drags a file onto the window.
However, I'm having trouble with the event propagation. When I set the overlay to display: block
it appears to fire off a dragleave
event and then another dragenter
and then another dragleave
again, so it's always in a post-dragleave state. Of course I call e.stopPropagation()
and e.preventDefault()
on the event object, but it doesn't seem to make a difference.
The console.log()
output when you drag something over the window:
dragenter
dragenter
dragleave
dragenter
dragleave
The css. #overlay
is set to display: none
by default, but will show if body
has the dragenter
class:
body {
position: absolute;
height: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: 0;
padding: 0;
}
#overlay {
position: absolute;
height: auto;
width: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url(bg.png) repeat-x top right, url(bg.png) repeat-x bottom left, url(bg.png) repeat-y top right, url(bg.p
ng) repeat-y bottom left;
display: none;
}
body.dragenter #overlay {
display: block;
}
The JavaScript; add the 'dragenter' class on dragenter
and removes it on dragleave
:
$(document).on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
console.log('dragenter');
$(document.body).addClass('dragenter');
});
$(document).on('dragleave', function (e) {
e.stopPropagation();
e.preventDefault();
console.log('dragleave';
$(document.body).removeClass('dragenter');
});
The html:
<body>
<div id="overlay">...</div>
...
</body>
Share
Improve this question
edited Jun 5, 2022 at 22:39
Brian Tompsett - 汤莱恩
5,89372 gold badges61 silver badges133 bronze badges
asked Jan 21, 2012 at 5:59
ʞɔıuʞɔıu
48.4k35 gold badges108 silver badges154 bronze badges
4 Answers
Reset to default 6Your overlay takes up the whole document size, when you drag in, it fills up its space and your mouse is effectively taken out of the body and is now over the overlay. This triggers a mouseleave/mouseenter loop. To achieve what you are after, you may want to bind the event to a transparent overlay with a high z-index over the visible overlay which has a lower z-index. This would keep the event in the highest element.
Example:
http://jsfiddle/scottux/z7yaB/
Thanks to Scottux, that led me onto the right track.
Only problem was it also covered up the rest of the page, so none of the elements or inputs were clickable. I had to hide #dragOverlay by default with "display: none" and display it on this event
// Display an overlay when dragging a file over
$('*:visible').live('dragenter', function(e) {
e.stopPropagation();
$('body').addClass('drag-enter');
});
var dropZone = function() {
var self = this;
this.eTimestamp = 0;
this.showDropZone = function(e) {
e.stopPropagation();
e.preventDefault();
if (self.eTimestamp + 300 < e.timeStamp) {
$("#coverDropZone").show();
self.eTimestamp = e.timeStamp;
}
return false;
}
this.hideDropZone = function(e) {
e.stopPropagation();
e.preventDefault();
if (self.eTimestamp + 300 < e.timeStamp) {
$("#coverDropZone").hide();
self.eTimestamp = e.timeStamp;
}
return false;
}
this.showImage = function(e) {
e.stopPropagation();
e.preventDefault();
console.log(e);
return false;
}
document.addEventListener('dragenter', self.showDropZone, false);
document.addEventListener('dragleave', self.hideDropZone, false);
document.addEventListener('drop', self.showImage, false);
}
The simple solution is instead of using dragenter use dragover
dragover This event is fired as the mouse is moved over an element when a drag is occurring. Much of the time, the operation that occurs during a listener will be the same as the dragenter event.