Современный JavaScript вместе с  HTML5 предоставляет возможность обработки событий перетаскивания и "бросания" элементов (Drag & Drop) благодаря наличию нескольких событий, которые определяют начало и конец перетаскивания, момент попадания в целевой объект и момент отпускания, или "бросания" элемента над целевым элементом.

Давайте рассмотрим на примере, как осуществляется обработка событий Drag & Drop в JavaScript, какие это события, и как мы можем их использовать для перетаскивания нескольких элементов.

Виды событий для перетаскивания элементов

Для перетаскиваемого элемента:

  1. ondragstart - возникает в начале перетягивания объекта;
  2. ondragend - возникает в конце перетягивания элемента;
  3. ondrag - возникает, когда элемент перетаскивается.
Важно: для перетаскиваемого объекта вам нужно добавить либо атрибут draggable="true", либо написать строку elem.draggable = true в JavaScript-коде.

Для целевого элемента, в который мы будем "бросать" перетягиваемый элемент:

  1. ondragenter - происходит, когда перетаскиваемый элемент входит в пределы целевого элемента, в который его перемещают;
  2. ondragleave - происходит, когда перетаскиваемый элемент покидает пределы целевого объекта для перемещения.
  3. ondragover - происходит, когда перетаскиваемый элемент находится над целевым объектом для перемещения.
  4. ondrop - когда перетаскиваемый элемент "бросают" в целевой объект, т.е. вы отпускаете курсор мыши над целевым объектом

В примере ниже мы назначим для перетаскиваемых объектов голубой цвет фона, а для целевых объектов, внутри которых должен оказаться перетаскиваемый элемент, - белый цвет фона.

See the Pen Drag & Drop JS by Elen (@ambassador)on CodePen.

Что касается самого процесса перетаскивания, то мы будем назначать обработчики событий с помощью метода addEventListener(), как более современного, чем ondragstart в виде безымянной или именованной функции, причем само событие внутри этого метода будем указывать без приставки "on". Кроме того, каждый обработчик нужных нам событий содержит вывод названия этого события в консоль, так что вы можете посмотреть, когда и сколько раз каждое из этих событий наступает. Для этого имеет смысл открыть пример в новой вкладке без дополнительных панелей с кодом.

Для начала нам нужно будет определиться с набором элементов, к которым мы получим доступ в JS-коде благодаря методу document.querySelectorAll():

Кроме того, мы объявим переменную dragElem, которая впоследствии будет содержать ссылку на перетаскиваемый элемент.

Обработка начала и конца перетаскивания

Для элементов с классом .block мы добавляем слушатели событий начала и конца перетаскивания (dragstart и dragend), перебирая эти элементы с помощью метода forEach():

Что мы делаем в функциях-обработчиках событий начала и конца перетаскивания для draggable-элементов? В функции, вызываемой при наступлении события dragstart с именем startDragBlock, мы указываем ссылку на перетаскиваемый объект в переменной dragElem , а затем назначаем этому объекту класс hide, который "прячет" наш перетаскиваемый объект за счет изменения свойства display. Однако, для того, чтобы это происходило не моментально, мы помещаем строку this.classList.add('hide') внутрь функции, вызываемой в методе setTimeout().

В конце перетаскивания мы удаляем класс hide, отображая наш объект, и присваиваем переменной dragElem значение null, показывая таким образом, что перетаскивать объект мы уже закончили.

Обработка событий перетаскивания для целевого элемента

В целевой элемент мы должны "бросить" перетаскиваемый в данный момент объект. Здесь нам придется использовать 2 функции с почти одинаковым кодом при обработке событий dragenter (перетаскиваемый объект попал на "территорию" целевого элемента) и перемещается над ним (событие dragover). Если вы посмотрите в консоль, то увидите, что событие dragover наступает значительно чаще, чем dragenter. Это и понятно, т.к. даже небольшие движения мышкой приводят к наступлению этого события.

Кроме того, особенностью этих событий является то, что для реализации нормального процесса перетаскивания, желательно для них отменять поведение браузера по умолчанию с помощью метода event.preventDefault():

При наступлении событий dragenter  и dragover мы добавляем класс hover, который "подсвечивает" целевой элемент светло-голубым цветом и с помощью псевдоэлемента ::before сообщает, что уже пора отпускать курсор мыши.

Обработка события dragleave подразумевает, что перетаскиваемый элемент покинул пределы области целевого объекта. Поэтому в нашем примере мы удаляем класс .hover из списка классов для элемента .box, убирая таким образом подсветку из светло-голубого фона.

То же самое нам нужно сделать в том случае, когда пользователь отпустил курсор с перетаскиваемым элементом над целевым объектом и сгенерировал таким образом событие drop. Но здесь, помимо удаления класса, мы еще и помещаем перетаскиваемый элемент внутрь целевого элемента с помощью метода append().

Обратите внимание на то, что перетаскивать объекты можно и в тот момент, когда они уже находятся в одном из блоков с классом .box.

Примеры:

Перетаскиваемое изображение

В этом примере вам нужно перетащить и "бросить" изображение в один из элементов с классом .box. Здесь также меняется класс блока, над которым находится перетаскиваемый объект.

See the Pen Drag & Drop Image in JavaScript by Elen (@ambassador) on CodePen.

Перетаскиваемый список

Еще один пример, основанный на обработке событий Drag & Drop, но с более сложной логикой от Brad Traversy. Здесь список построен на основе массива из богатейших людей мира, который при выводе на экран перемешан в случайном порядке. С помощью обработки событий по перетаскиванию элементов нужно сформировать правильный список, который представлен в начальном массиве. Правильность построения этого списка можно проверить кликом по кнопке "Проверить список".

Здесь есть и работа с такими методами массивов, как map() и sort(), а также со свойством classList, который помогает добавлять или удалять классы при перетаскивании элементов.

See the Pen Draggable List by Elen (@ambassador) on CodePen.

Автор: Админ

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *