Подтвердить что ты не робот

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.

4b9b3361

Ответ 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" срабатывает.

Думая о загрузке файлов, я создал виджет, который позволяет:

  1. Перетащите файлы рабочего стола, используя $ _FILES
  2. Перетащите в браузер изображения/элементы или URL, используя $ _POST и cURL
  3. Прикрепите файл устройства с помощью кнопки, используя $ _FILES
  4. Используйте ввод для записи/вставки изображений/элементов 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>