JQuery.on( "drop" ) не срабатывает
Я пытаюсь реализовать перетаскивание файлов с рабочего стола в окне браузера. Я использовал jQuery для присоединения трех событий к элементу HTML, как в приведенном ниже коде:
$("html").on("dragover", function() {
$(this).addClass('dragging');
});
$("html").on("dragleave", function() {
$(this).removeClass('dragging');
});
$("html").on("drop", function(event) {
event.preventDefault();
event.stopPropagation();
alert("Dropped!");
});
События "dragover" и "dragleave" работают нормально, показывая рамку вставки вокруг всей страницы, когда я перетаскиваю файл поверх его удаления, если я снова вытащу файл.
Однако событие "drop" вообще не срабатывает, выпадающий файл просто открывается в окне браузера.
Кто-нибудь знает, почему это событие не стреляет?
Btw, я тестирую это в последней версии Chrome и использую jQuery 1.10.2.
Ответы
Ответ 1
Вам нужно отменить все события
$("html").on("dragover", function(event) {
event.preventDefault();
event.stopPropagation();
$(this).addClass('dragging');
});
$("html").on("dragleave", function(event) {
event.preventDefault();
event.stopPropagation();
$(this).removeClass('dragging');
});
$("html").on("drop", function(event) {
event.preventDefault();
event.stopPropagation();
alert("Dropped!");
});
Ответ 2
В дополнение к христианскому решению это можно сократить до:
$('#my-dropzone')
// crucial for the 'drop' event to fire
.on('dragover', false)
.on('drop', function (e) {
// do something
return false;
});
Ответ 3
В дополнение к решению JimmyBlu это можно сократить до:
$('selector').on('dragover drop', false);
Ответ 4
По-видимому, эта проблема является более повторяющейся, чем я думал, так как я нашел по крайней мере 5 вопросов, связанных с той же темой (и я отвечу на все вопросы, связанные с этой проблемой).
В отличие от "наведения мыши", события "dragover" и "dragleave" не рассматривают дочерние элементы как единое целое, поэтому каждый раз, когда мышь проходит над любым из дочерних элементов, "dragleave" срабатывает.
Думая о загрузке файлов, я создал виджет, который позволяет:
- Перетащите файлы рабочего стола, используя $ _FILES
- Перетащите в браузер изображения/элементы или URL, используя $ _POST и cURL
- Прикрепите файл устройства с помощью кнопки, используя $ _FILES
- Используйте ввод для записи/вставки изображений/элементов URL с помощью $ _POST и cURL
![enter image description here]()
Проблема: поскольку все, как входные данные, так и изображения, находятся внутри дочерних элементов DIV, "dragleave" был запущен, даже если он не покинул пунктирную линию. Использование атрибута "pointer-events: none" не является альтернативой, поскольку методы 3 и 4 должны инициировать события "onchange".
Решение? Перекрывающийся DIV, который покрывает весь drop-контейнер, когда мышь входит, и единственный с дочерними элементами с "pointer-events: none".
Структура:
- div # drop-container: основной div, сохранить все вместе
- div # drop-area: слушатель "dragenter" и промежуточный триггер # drop-pupup
- div # drop-pupup: на том же уровне, что и # drop-area, "dragenter", "dragleave" и "drop" слушатель
Затем, когда мышь входит, перетаскивая элемент в # drop-area, сразу же показывается # drop-pupup вперед и последовательно события находятся в этом div, а не в начальном получателе.
![enter image description here]()
Вот код JS/jQuery. Я позволил себе покинуть PoC, поэтому не теряйте все потерянное время.
jQuery(document).on('dragover', '#drop-area', function(event) {
event.preventDefault();
event.stopPropagation();
jQuery('#drop-popup').css('display','block');
});
jQuery(document).on('dragover dragleave drop', '#drop-popup', function(event) {
event.preventDefault();
event.stopPropagation();
console.log(event.type);
// layout and drop events
if ( event.type == 'dragover') {
jQuery('#drop-popup').css('display','block');
}
else {
jQuery('#drop-popup').css('display','none');
if ( event.type == 'drop' ) {
// do what you want to do
// for files: use event.originalEvent.dataTransfer.files
// for web dragged elements: use event.originalEvent.dataTransfer.getData('Text') and CURL to capture
}
}
});
body {
background: #ffffff;
margin: 0px;
font-family: sans-serif;
}
#drop-container {
margin: 100px 10%; /* for online testing purposes only */
width: 80%; /* for jsfiddle purposes only */
display: block;
float: left;
overflow: hidden;
box-sizing: content-box;
position: relative; /* needed to use absolute on #drop-popup */
border-radius: 5px;
text-align: center;
cursor: default;
border: 2px dashed #000000;
}
#drop-area {
display: block;
float: left;
padding: 10px;
width: 100%;
}
#drop-popup {
display: none;
box-sizing: content-box;
position: absolute;
width: 100%;
top: 0;
left: 0;
background: linear-gradient(to BOTTOM, rgba(245, 245, 245, 1) , rgba(245, 245, 245, 0));
height: 512px;
padding: 20px;
z-index: 20;
}
#drop-popup > p {
pointer-events: none;
}
<html>
<head>
<title>Drag and Drop</title>
</head>
<body>
<div id="drop-container">
<div id="drop-area">
<p>Child paragraph content inside drop area saying "drop a file or an image in the dashed area"</p>
<div>This is a child div No. 1</div>
<div>This is a child div No. 2</div>
</div>
<div id="drop-popup">
<p>This DIV will cover all childs on main DIV dropover event and current P tag is the only one with CSS "pointer-events: none;"</p>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" type="text/javascript"></script>
</body>
<html>