обзор
У меня есть следующий HTML - структура , и я приложил dragenter
и dragleave
событие к <div id="dropzone">
элементу.
<div id="dropzone">
<div id="dropzone-content">
<div id="drag-n-drop">
<div class="text">this is some text</div>
<div class="text">this is a container with text and images</div>
</div>
</div>
</div>
проблема
Когда я перетаскиваю файл поверх <div id="dropzone">
, dragenter
событие запускается, как и ожидалось. Однако, когда я перемещаю мышь над дочерним элементом, например <div id="drag-n-drop">
, dragenter
событие запускается для <div id="drag-n-drop">
элемента, а затем dragleave
событие запускается для <div id="dropzone">
элемента.
Если я снова наведу указатель мыши на <div id="dropzone">
элемент, dragenter
событие снова будет запущено, что круто, но затем dragleave
событие будет запущено для оставленного дочернего элемента, поэтому выполняется removeClass
инструкция, что не круто.
Такое поведение проблематично по 2 причинам:
Я только прикрепление
dragenter
иdragleave
к<div id="dropzone">
так что я не понимаю , почему дети элементы имеют эти события присоединенные также.Я все еще перетаскиваю
<div id="dropzone">
элемент, нависая над его дочерними элементами, поэтому я не хочуdragleave
стрелять!
jsFiddle
Вот jsFiddle, с которым можно повозиться: http://jsfiddle.net/yYF3S/2/
Вопрос
Итак ... как сделать так, чтобы при перетаскивании файла поверх <div id="dropzone">
элемента dragleave
он не срабатывал, даже если перетаскивал какие-либо дочерние элементы ... он должен срабатывать только при выходе из <div id="dropzone">
элемента зависание / перетаскивание в любом месте в пределах границ элемента не должно вызывать dragleave
событие.
Мне нужно, чтобы он был совместим с разными браузерами, по крайней мере, в браузерах, которые поддерживают перетаскивание HTML5, поэтому этот ответ не подходит.
Кажется, что Google и Dropbox выяснили это, но их исходный код минимизирован / сложен, поэтому я не смог понять это из их реализации.
e.stopPropagation();
Ответы:
Если вам не нужно привязывать события к дочерним элементам, вы всегда можете использовать свойство pointer-events.
источник
:hover
стили или обработчики событий щелчка). Если вы хотите сохранить эти события, вот еще один обходной путь, который я использовал: bensmithett.github.io/dragster.dropzone * {pointer-events: none;}
$('.element').addClass('dragging-over')
к элементу, который вы перетаскиваете, и$('.element').removeClass('dragging-over')
когда вы перетаскиваете. Тогда в вашем CSS вы можете иметь.element.dragging-over * { pointer-events: none; }
. Это удаляет события указателя из всех дочерних элементов только при перетаскивании.Я наконец нашел решение, которым я доволен. На самом деле я нашел несколько способов сделать то, что я хочу, но ни один из них не был настолько успешным, как текущее решение ... в одном решении я испытывал частое мерцание в результате добавления / удаления границы
#dropzone
элемента ... в другом - границы никогда не удалялся, если вы зависли от браузера.В любом случае, мое лучшее хакерское решение таково:
Это работает довольно хорошо, но проблемы возникли в Firefox, потому что Firefox вызывался дважды,
dragenter
поэтому мой счетчик был выключен. Но, тем не менее, это не очень элегантное решение.Тогда я наткнулся на этот вопрос: как обнаружить событие dragleave в Firefox при перетаскивании за пределы окна
Поэтому я взял ответ и применил его к моей ситуации:
Это чисто и элегантно и, похоже, работает во всех браузерах, которые я тестировал до сих пор (еще не тестировал IE).
источник
stopPropagation()
иpreventDefault()
является предпочтительным. Я бы бросилreturn false
.Это немного некрасиво, но это работает, черт возьми! ...
В вашем обработчике «dragenter» сохраните event.target (в переменной внутри вашего замыкания или где-то еще), затем в вашем обработчике «dragleave» запустите ваш код, только если event.target === тот, который вы сохранили.
Если ваш 'dragenter' срабатывает, когда вы этого не хотите (т.е. когда он входит после выхода из дочерних элементов), то в последний раз, когда он срабатывает до того, как мышь покидает родительский элемент, он находится на родительском элементе, поэтому родительский элемент всегда будет последний «драгентер» перед намеченным «драглайвом».
источник
Сначала я согласился с людьми, отказывающимися от
pointer-events: none
подхода. Но потом я спросил себя:В моем случае, у меня много чего происходит, например, при наведении курсора на кнопки для дополнительных действий, встроенного редактирования и т. Д. Однако во время перетаскивания ничего из этого не требуется или даже не требуется .
В моем случае я использую что-то вроде этого, чтобы выборочно отключить события указателя для всех дочерних узлов родительского контейнера:
Используйте свой любимый подход , чтобы добавить / удалить класс
dragging-in-progress
вdragEnter
/dragLeave
обработчиков событий, как я сделал или сделать то же самоеdragStart
, и др. и др.источник
dragstart
событие и удалите егоdragend
.Это похоже на ошибку Chrome.
Единственный обходной путь, о котором я мог подумать, - это создать прозрачный элемент наложения для захвата ваших событий: http://jsfiddle.net/yYF3S/10/
JS :
HTML :
источник
Проблема в том, что ваши элементы внутри дропзоны, конечно, являются частью дропзоны, и когда вы входите в дочерние элементы, вы оставляете родителя. Решить это нелегко. Вы можете попробовать добавить события к детям, добавив ваш класс снова к родителю.
Ваши события будут по-прежнему срабатывать несколько раз, но никто не увидит.
// Редактировать: использовать событие dragmove, чтобы навсегда перезаписать событие dragleave:
Определите событие Dragleave только для dropzone.
источник
dragleave
... когда я оставляю ребенка, я все еще могу быть в пределах родителя,#dropzone
но это не вызоветdragenter
событие снова :(dragleave
событие для дочернего элемента, который только что вышел, поэтому снова выполняетсяremoveClass
инструкцияdragleave
только для#dropzone
... если бы я мог, у меня не было бы этой проблемы.Как упоминалось в этом ответе , вы можете запретить дочерним узлам запускать события, но если вам нужно привязать некоторые события, сделайте следующее:
И добавьте это в свой код JS:
источник
Если вы используете jQuery, проверьте это: https://github.com/dancork/jquery.event.dragout
Это действительно потрясающе.
РЕДАКТИРОВАТЬ: на самом деле, я не думаю, что это зависит от jQuery, вы можете просто использовать код даже без него.
источник
dragleave
даже если я не покинул родительскую зону сброса.dragout
было единственным решением, которое работало для меня.@ Христо У меня есть более элегантное решение. Проверьте, если это то, что вы могли бы использовать.
Ваши усилия не были потрачены впустую в конце концов. Сначала мне удалось использовать ваш, но у меня были разные проблемы в FF, Chrome. Потратив так много часов, я понял, что это предложение работает точно так, как задумано.
Вот как это делается. Я также воспользовался визуальными подсказками, чтобы правильно направлять пользователей о зоне сброса.
источник
var dropZoneHideDelay=70, dropZoneVisible=true;
dropZoneHideDelay, dropZoneVisible
необходимы для двух'on'
событий документа в моей реализации.Мои два цента: скройте слой над зоной сброса, затем покажите его при перетаскивании и наведите курсор на него.
Демо: https://jsfiddle.net/t6q4shat/
HTML
CSS
JS
источник
Так что для меня подход
pointer-events: none;
не сработал ... Итак, вот мое альтернативное решение:Таким образом, это невозможно для
dragleave
родительского (дочернего) илиdragover
дочернего элемента. надеюсь это поможет :)* .Active-класс, который я добавляю, когда я
dragenter
илиdragleave
. Но если вы работаете без этого, просто не посещайте занятия.источник
Супер простое быстрое решение для этого, не проверено, но работает в Chrome прямо сейчас.
Извините, Coffeescript.
Это исправляет ошибку мерцания Chrome или, по крайней мере, ее перестановку, которая вызывала у меня проблемы.
источник
Этот ответ можно найти здесь:
HTML5 dragleave срабатывает при наведении на дочерний элемент
источник
Моя версия:
С этим макетом:
Я сделал дамп классов элементов для
e.target
,e.currentTarget
,e.relatedTarget
для обоихdragover
иdragleave
событий.Он показал мне, что при выходе из родительского блока (
.dropzone
)e.relatedTarget
не является дочерним по отношению к этому блоку, поэтому я знаю, что я вне зоны сброса.источник
Здесь одно из самых простых решений ● ︿ ●
Посмотрите на эту скрипку <- попробуйте перетащить какой-нибудь файл внутрь коробки
Вы можете сделать что-то вроде этого:
По этому вы уже должны знать, что здесь происходит.
Знаете, просто посмотрите на скрипку.
источник
У меня была похожая проблема, и я исправил ее следующим образом:
Проблема: функция drop (ev) запускается, когда пользователь удаляет элемент в «зоне удаления» (элемент ul), но, к сожалению, также когда элемент сбрасывается в одном из его дочерних элементов (элементов li).
Исправление:
источник
Я пытался реализовать это сам для коробки загрузки файлов, где цвет коробки изменился бы, когда пользователи перетаскивали файл в пространство.
Я нашел решение, которое представляет собой хорошее сочетание Javascript и CSS. Скажем, у вас есть зона сброса
div
с идентификатором#drop
. Добавьте это к вашему Javascript:Затем добавьте это в свой CSS, чтобы инактивировать всех детей, которые будут заниматься
.inactive
:Таким образом, дочерние элементы будут неактивны до тех пор, пока пользователь перетаскивает элемент над полем.
источник
Я не чувствовал себя удовлетворенным ни одним из обходных путей, представленных здесь, потому что я не хочу терять контроль над дочерними элементами.
Поэтому я использовал другой логический подход, переводя его в плагин jQuery, который называется jquery-draghandler . Он абсолютно не манипулирует DOM, гарантируя высокие характеристики. Его использование просто:
Он без проблем справляется с проблемой, не ставя под угрозу функциональность DOM.
Скачать, подробности и объяснения в своем репозитории Git .
источник
frame
s, и ваш элемент находится на границе этого. В таком случае я не предлагаю такой подход.Мне действительно нравится то, что я вижу на https://github.com/lolmaus/jquery.dragbetter/но хотел поделиться возможной альтернативой. Моя общая стратегия заключалась в том, чтобы применить стиль фона к зоне сброса (не к ее дочерним элементам) при перетаскивании ее или любого ее дочернего элемента (посредством всплытия). Затем я удаляю стиль, когда перетаскиваю зону сброса. Идея заключалась в том, что при переходе к ребенку, даже если я удаляю стиль из дропзоны, когда покидаю его (огни драконьей волны), я просто повторно применяю стиль к родительской дропзоне при перетаскивании любого потомка. Проблема, конечно, заключается в том, что при переходе из промежуточной зоны в дочернюю из зоны перетаскивания драгентер срабатывает перед дочерним элементом, поэтому мои стили были применены не по порядку. Решением для меня было использование таймера, чтобы принудительно вернуть событие dragenter обратно в очередь сообщений, что позволило мне обработать его ПОСЛЕ завершения перетаскивания. Я использовал замыкание для доступа к событию по обратному вызову таймера.
Похоже, что это работает в Chrome, то есть Firefox и работает независимо от количества детей в dropzone. Мне немного не по себе из-за тайм-аута, гарантирующего повторное упорядочение событий, но, похоже, он хорошо работает для моего варианта использования.
источник
Я пытался реализовать это сам, и я не хотел Jquery или любой плагин либо.
Я хотел обработать загрузку файла следующим образом:
Структура файлов:
--- / загружает {загружает каталог}
--- /js/slyupload.js {файл javascript.}
--- index.php
--- upload.php
--- styles.css {просто немного стайлинга ..}
HTML-код:
Тогда это прикрепленный файл Javascript :: 'js / slyupload.js'
CSS:
источник
Извините, это javascript, а не jquery, но для меня это самый логичный способ решить эту проблему. Браузер должен вызывать dropleave (предыдущего элемента) перед dropenter (или новым элементом, поскольку что-то не может ввести что-то еще, прежде чем покинуть первое, я не понимаю, почему они это сделали! Так что вам просто нужно отложить де дроплэйв так:
И капельница случится после капли, вот и все!
источник
Используйте
greedy : true
для ребенка как функциюdroppable
. Затем запускается только событие, щелкнувшее по первому слою.источник