Вот чего я пытаюсь достичь:
На странице есть несколько dropzones. Пользователи должны иметь возможность перетаскивать файлы из своей ОС и переносить их в дескрипторы.
Dropzones выделяются при перетаскивании. Существует два визуально разных типа выделения: "Цель" (например, элемент очерчен пунктирной линией) и "Hover" (например, элемент получает яркий фон).
Выделение цели применяется/удаляется на/из всех разбросов одновременно:
- Когда пользователь перетаскивает файл по странице, все dropzones должны быть выделены с помощью выделения Target.
- Когда пользователь перетаскивает файл за пределы страницы или отменяет операцию перетаскивания или выполняет перетаскивание, то выделение цели следует удалить из всех дескрипторов.
Подсветка Hover должна применяться только к одной dropzone:
- Когда пользователь перетаскивает файл над dropzone, эта dropzone должна быть выделена подсветкой Hover.
- Когда пользователь перетаскивает файл за пределы этой зоны смены или отменяет операцию перетаскивания или выполняет удаление, то выделение цели следует удалить из dropzone.
Когда пользователь бросает файл в dropzone, имя файла должно появиться внутри dropzone.
Когда пользователь бросает файл на странице за пределами dropzones, все выделения выделенных областей должны быть удалены, и ничего больше не должно произойти. В частности, броузер не открывается браузером.
Решение должно быть настолько изящным, насколько это возможно: грязные хаки, такие как использование тайм-аутов, подсчет
dragenter
/dragleave
и повторное использование подсветки для каждогоdragover
не приветствуются.Решение должно работать в последних версиях основных браузеров.
Вот чего мне удалось добиться до сих пор: попытка 1, попытка 2.
Проблемы, которые я успешно разрешил
-
Если вы удалили файл за пределами dropzone, браузер открыл его.
Решение:
$(document).on('dragover drop', function (e) { e.preventDefault(); });
-
Отбрасывание файла в dropzone создает событие
drop
с целью, равной ребенку dropzone, а не самой dropzone.Решение:
$dropzones.on( 'drop', function (event) { /* ... */ // Find the dropzone responsible for the event $targetDropzone = $(event.target).closest($dropzones); /* ... */ });
-
Наведение файла над детьми
dragleave
генерирует несколько событийdragleave
, поэтому подсветка Hover исчезает сразу (подсветка Hover должна быть удалена из dropzone, когда курсор мыши покидает dropzone, поэтому он связан с событиемdragleave
).Решение: используйте событие
dragout
вместоdragleave
.dragout
- это настраиваемое событие, предоставляемое плагином jquery.event.dragout. Это событие не будет срабатывать для дочерних элементов.
Неразрешенные проблемы
-
Невозможно обнаружить момент, когда перетаскиваемый файл покидает
document
илиwindow
, чтобы можно было выполнить команду "удалить целевую подсветку".Пользовательский плагин
dragout
предназначен для работы только для детей<body>
. Он не работает ни дляdocument
ни дляwindow
.Официальные
dragstart
иdragend
не будут работать вообще для перетаскивания файлов. Это ожидаемое поведение. :(События
dragenter
иdragleave
связанные сdocument
, запускаются не только тогда, когда указатель мыши входит/выходит из документа, но также и когда указатель вводит/оставляет документы. Хуже всего,event.target
первого появления$(document).on('dragenter')
может отображаться как один элемент (это может бытьdocument
или его дочерний элемент), а последнее вхождение$(document).on('dragleave')
может отображаться как другой элемент, поэтому вы не можете решить проблему, сравниваяevent.target
s.Из-за этих проблем я не смог изящно отслеживать момент, когда мышь покидает документ.
Я попытался использовать плагин draghover, предназначенный для решения этой проблемы. Мне удалось заставить его работать (протестировано только в Chrome), но после первого успешного падения он перестанет работать. См. Неудачную попытку здесь.
-
Хотя визуальное
dragenter
событиеdragenter
запускается многократно, пока файл парит над документом. Таким образом, подсветка применяется несколько раз, а не одна. -
Указатель мыши во время перетаскивания должен отображать значок браузера "Невозможно отбросить здесь" при зависании внешних зон, а значок "может отбросить здесь" при наведении курсора на паззы.
UPD 2014-03-16 15:30, ответ Яну Быткеку ответ
Привет товарищ! Благодарим вас за подробный ответ. К сожалению, есть ряд проблем с вашим решением.
1.
- Невозможно обнаружить момент, когда перетаскиваемый файл покидает документ или окно, чтобы можно было выполнить команду "удалить целевую подсветку".
$ (document).on('dragleave',... должен сделать трюк, см. скрипку ниже.
Нет, это очень плохо.
Позвольте сказать, что вы слушаете события dragenter
и dragleave
на <body>
. Всякий раз, когда перетаскивание указателя мыши навешивается на край любого элемента, запускаются два события:
-
dragenter
на<body>
сevent.target
установленным на зависающий элемент; -
dragleave
on<body>
сevent.target
установленным для родителя зависающего элемента.
Я предположил, что выделение цели будет применяться с селектором .dropzone.target-higlighing
. Вы сделали остроумный трюк, применив подсветку Target с помощью селектора .target-highlighting.dropzone
.
Посмотрите на свой код:
$('body')
.on('dragenter', function (event) {
$(event.target).addClass('target-highlighting');
event.preventDefault();
})
.on('dragleave drop', function (event) {
$(event.target).removeClass('target-highlighting-class');
event.preventDefault();
})
Если dropzone находится в нескольких вложенных контейнерах, перетаскивание файла по контейнерам приведет к миграции мишени класса целевого выделения из самого внешнего контейнера в самый внутренний. Из-за того, что вы использовали .target-highlighting.dropzone
в CSS, похоже, что целевая подсветка стоит...
... пока вы не перетащите файл над элементом, который не является родителем dropzone. Это может быть боковая панель или сама капля. Когда это произойдет, .target-highlighting.dropzone
перестает применяться, и подсветка цели исчезает.
Это неприемлемо. Выделение цели должно появляться только тогда, когда файл перетаскивается на страницу и удаляется, когда файл вытаскивается из страницы или когда перетаскивание завершено (путем удаления или отмены).
2.
- Хотя визуальное отображение невозможно, событие dragenter запускается многократно, пока файл парит над документом. Таким образом, подсветка применяется несколько раз, а не одна.
Событие запускается каждый раз, когда мышь вводит какой-либо элемент. Таким образом, когда вы перетаскиваете страницу, она вводит много элементов и срабатывает много раз. Чтобы этого избежать, вам нужно "отключить" все под каждой респирацией, есть два способа сделать это.
Во-первых, это использование событий css-указателей, это самое элегантное, но менее ориентированное на браузер решение. Он работает с самыми последними, и я лично его люблю.
Во-вторых, чтобы создать прозрачный оверлей поверх вершины droparea - мышь ударит только это, а не элементы под ним, что предотвратит появление нескольких событий перетаскивания.
Эти решения приемлемы для запуска подсветки Hover, которая применяется, когда указатель мыши находится внутри dropzone. (BTW, я нашел более изящное решение для этого: dragout
событий dragout
, см. № 3 в разделе "Разрешенные проблемы" выше).
Но они совершенно не подходят для подсветки Target, которая должна применяться, когда указатель мыши находится внутри и за пределами dropzone. Вам нужно будет отключить события мыши (либо с помощью pointer-events: none;
либо наложения) для всей страницы, а dropzones больше не будут принимать капли.
3.
- Указатель мыши во время перетаскивания должен отображать значок браузера "Невозможно отбросить здесь" при зависании внешних зон, а значок "может отбросить здесь" при наведении курсора на паззы.
Я не на 100% уверен в этом, но на MAC я не могу изменить значок при перетаскивании, так как он использует специальный по умолчанию. Я предполагаю, что этого не может быть сделано, но хотелось бы узнать иначе.
Я заметил, что то, что я прошу, уже работает в Chrome! См. Ссылку ниже.
Однако Firefox не изменил бы указатель мыши. :(
Лучший шаблон для тестирования решений на
Есть также довольно красивые библиотеки, такие как http://www.dropzonejs.com/, с которыми у меня нет опыта, но они являются хорошим источником "вдохновения".
Я видел этот плагин. Он не разрешает проблемы, описанные выше. Выделение цели не применяется вообще, и подсветка Hover мерцает при перетаскивании файла над dropzone.
Кроме того, я не могу использовать его, потому что у меня есть собственная реализация dropzone. Например, моя dropzone позволяет пользователям сортировать файлы, добавленные в dropzone. Мне нужно только решение для обработки событий перетаскивания.
Мои личные рекомендации состоят в том, чтобы использовать подход плагинов per-droparea, а не подход на странице, как в ваших примерах. Эти компоненты, как правило, становятся довольно большими, когда вы добавляете логику загрузки, проверку и т.д.
Вы абсолютно правы. В моем проекте я использую замечательный jQuery UI Widget Factory. Это метод определения плагинов jQuery, которые ведут себя отдельно друг от друга.
Здесь я создал лучший шаблон для тестирования дальнейших решений: http://jsbin.com/rupaloba/4/edit?html,css,js,output
Надеюсь, это не слишком сложно.