Знакомство с техникой Drag-and-Drop и механизмом ее реализации с помощью JavaScript. Данный обзор не претендует на полноту покрытия материала. Задача статьи - познакомиться с созданием Drag-and-Drop на JavaScript. Понять сам принцип механизма и научиться применять основные инструменты для его реализации.
Определение Drag-and-Drop
Сам механизм Drag-and-Drop интуитивно понятен - “схватил-перетащил-бросил”. Преимущество внедрения Drag-and-Drop в интерфейсы заключается в упрощении реализации задач; в уменьшении количества пунктов меню типа “Copy-Paste”.
События Drag-and-Drop
Механизм Drag-and-Drop имеет в своем составе целую группу событий, с помощью которых можно контролировать процесс перетаскивания:
- пользователь начинает перетаскивание элемента1
dragstart
- перетаскиваемый элемент входит в область целевого объекта1
dragenter
- перетаскиваемый элемент перемещается в области целевого объекта1
dragover
- перетаскиваемый элемент покидает область целевого объекта1
dragleave
- момент начала процесса перетаскивания объекта1
drag
- момент, когда отпускается зажатая клавиша мыши (перетаскиваемый объект “роняется”)1
drop
- момент завершения процесса перетаскивания объекта1
dragend
Объект dataTransfer
Механизм Drag-and-Drop также имеет в своем составе объект dataTransfer, который служит для вспомогательных целей. В этом объекте хранится необходимая информация о событии перетаскивания. Помимо этого, в объект dataTransfer можно добавлять данные; а также считывать из него данные.
Свойства (наиболее важные) объекта dataTransfer:
- задаем тип перетаскивания, которое пользователь может выполнять с элементом1
dataTransfer.effectAllowed
- задаем внешний вид курсора мыши в соответствии с заданным типом перетаскивания1
dataTransfer.dropEffect
Методы (наиболее важные) объекта dataTransfer:
- добавляет данные в нужном формате1
setData()
- удаляет данные1
clearData()
- устанавливает изображение для перетаскивания с координатами курсора (0, 0 — левый верхний угол)1
setDragImage()
- возвращает данные1
getData()
Ниже будет рассматриваться практический пример реализации Drag-and-Drop на JavaScript.
HTML разметка
Базовая HTML-разметка будет простой:
Что для чего служит в этой разметке?
Заголовок
будет отображать текущее состояние процесса Drag-and-Drop. В него мы будет отправлять информацию о текущем состоянии Drag-and-Drop при помощи событий, о который говорилось выше.1
id="dropStatus"
Заголовок
служит просто для декоративных целей.1
id="dropTitle"
Блок
является целевой областью - в нее мы будет перетаскивать объекты.1
id="dropZone"
Объекты
, 1
id="object1"
, 1
id="object2"
- это перетаскиваемые объекты; их мы будем перемещать в область блока 1
id="object3"
.1
id="dropZone"
Кнопка
будет выводить информацию об перемещенных объектах.1
id="readDropZone"
В итоге разметка совместно со стилями будут выглядеть таким образом - JavaScript - Drag’n’Drop - Part 1.
JavaScript - разбираемся с событиями
Прежде чем детально рассматривать работу каждой из будущих функций по обработке событий, мне кажется, будет лучше просто понять, какие события и куда мы будем “вешать”.
Итак, начнем с перетаскиваемых элементов
, 1
id="object1"
, 1
id="object2"
. На каждый из них мы повесим два события:1
id="object3"
- событие начала процесса перетаскивания элемента1
dragstart
- событие окончания процесса перетаскивания элемента1
dragend
Для каждого из элементов, при возникновении на нем события, мы будем запускать соответствующую функцию
или 1
dragStart
:1
dragEnd
Обратим внимание на строку
- здесь мы динамически добавляем для всех элементов с классом 1
el.setAttribute('draggable', 'true');
атрибут 1
.objects
, тем самым делая (благодаря HTML5) эти элементы доступными для перетаскивания.1
draggable="true"
На элемент
мы “повесим” гораздо больше событий:1
id="dropZone"
- перетаскиваемый объект (например,1
dragenter
) входит в область целевого объекта (1
id="object1"
)1
id="dropZone"
- перетаскиваемый объект (например,1
dragleave
) выходит из области целевого объекта (1
id="object1"
)1
id="dropZone"
- перетаскиваемый объект (например,1
dragover
) перемещается внутри области целевого объекта (1
id="object1"
)1
id="dropZone"
- перетаскиваемый объект (например,1
drop
) помещается внутри целевого объекта (1
id="object1"
)1
id="dropZone"
И конечно же, для каждого события будет своя функция. JavaScript-код в итоге будет выглядеть таким образом:
Ну и на кнопку
мы “повесим” обычный код с функцией 1
id="readDropZone"
:1
readZone
Если суммировать все вышесказанное, то общий вид handler’ов в нашем случае будет выглядеть таким образом:
Далее будет детально останавливаться на каждой из функций - что она делает и для чего.
Функция dragStart (event)
Начнем с начала и запустим функцию для обработки старта события перетаскивания - события
. Хочу сразу оговориться, что в процессе написания кода для обработки события перетаскивания важно четко представлять себе, какое событие и на каком элементе происходит.1
dragstart
В данном случае мы будем обрабатывать событие
, которое возникает на перетаскиваемом элементе (1
dragstart
, 1
id="object1"
или 1
id="object2"
- не важно).1
id="object3"
Событие
в момент своего возникновения автоматически генерирует объект dataTransfer, который (как мне кажется) можно в общих чертах сравнить с событийным объектом Event; последний также хранит в себе множество данных о произошедшем событии. Некоторыми методами и свойствами объекта Event мы воспользуемся в нашем примере:1
dragstart
Функция
при возникновении события “берет” элемент 1
dragStart
и методом 1
dropStatus
“пихает” внутрь него строку, часть которой представляет из себя значение атрибута 1
innerHTML
элемента, на котором произошло событие (1
id
).1
event.target
Для объекта dataTransfer задается значение его свойства
- 1
dropEffect
.1
move
В третьей строке для объекта dataTransfer с помощью метода
задается имя переменной 1
setData()
и значение для этой переменной - ID текущего элемента.1
text
Функции dragEnter(), dragLeave(), dragOver()
Три функции, каждая из которых отслеживает событие, возникающее на элементе
:1
dropZone
Первые две функции -
и 1
dragEnter (event)
очень похожи между собой. Каждая из них манипулирует содержимым заголовка 1
dragLeave (event)
, сигнализируя о происходящем событии.1
dropStatus
Третья функция
может показаться странной. Все ее назначение - это отмена действия по-умолчанию. Что это за действие по-умолчанию? Дело в том, что у браузеров имеется свой собственный (помимо HTML5) механизм реализации события перетаскивания Drag-and-Drop. И если его не отключить, то он не даст срабатывать нашему механизму.1
dragOver (event)
Функция dragDrop (event)
Самая большая и самая важная функция в нашем коде. Она также срабатывает на событие, возникающее на элементе
:1
dropZone
В строке
мы снова отменяем действие по-умолчанию. На этот раз это касается самого перетаскиваемого элемента - ведь он может быть ссылкой и браузер выполнит переход по ней (действие по-умолчанию), что нам совсем не нужно.1
event.preventDefault();
В строке:
… мы из объекта dataTransfer получаем ID перетаскиваемого элемента. Вы же помните, что в функции
с помощью строки:1
dragStart (event)
…мы его как раз получали?
Далее находим перетаскиваемый элемент по его ID:
И помещаем его внутрь текущего активного элемента:
Далее убираем у перетаскиваемого элемента атрибут
- он больше не перетаскиваемый. Визуально сигнализируем об этом, изменив вид курсора мыши:1
draggable
И сообщаем об изменившемся статусе в заголовке:
Отдельного упоминания стоит строка
. Это флаг, с помощью которого мы определяем, произошло ли событие 1
droppedIN = true;
или нет.1
drop
Может случиться так, что объект мы перетащили в область элемента
, но передумали его помещать туда. И “отпустили” перетаскиваемый элемент за областью элемента 1
dropZone
. В результате событие 1
dropZone
произошло, но событие 1
dragend
не выполнилось.1
drop
Такую ситуацию обрабатывает функция
:1
dragEnd()
Функция readZone ()
Последняя функция из нашего примера - это функция-счетчик. Ее задача - просто посчитать, сколько элементов на данный момент мы “бросили” в область
:1
dropZone
Нажимаем кнопку
и alert’ом последовательно выводим все элементы, помещенные внутрь объекта 1
dropButton
.1
dropZone
Вот, в принципе, и все, что можно вкратце сказать. Осталось только взглянуть на готовый пример работы кода - JavaScript - Drag’n’Drop - Part 2.
На этом все. Здоровая критика и полезные замечания только приветствуются.
Этот скромный обзор не смог бы появиться, если бы не было двух полезных для меня ресурсов:
Есть более детальный обзор и более интересный пример задачи на JavaScript Drag-and-Drop размещен здесь: