В этом руководстве вы узнаете об API Drag and Drop в JavaScript и о том, как использовать его для реализации простого приложения перетаскивания элементов.
HTML5 официально представил спецификацию перетаскивания. В большинстве современных веб-браузеров реализовано собственное перетаскивание на основе спецификации HTML5.
По умолчанию можно перетаскивать только изображение и текст. Чтобы перетащить изображение, просто нажмите и удерживайте кнопку мыши, а затем переместите его. Чтобы перетащить текст, вам нужно выделить текст и перетащить его так же, как перетаскивание изображения.
Спецификация HTML5 указывает, что почти все элементы можно перетаскивать. Чтобы сделать элемент перетаскиваемым, вы добавляете свойство draggable со значением true в его HTML-тег. Например:
<div class="item" draggable="true"></div>
События для перетаскиваемых элементов
Когда вы перетаскиваете элемент, эти события срабатывают в следующей последовательности:
dragstartdragdragend
Когда вы удерживаете кнопку мыши и начинаете двигать мышь, событие dragstart срабатывает на перетаскиваемом элементе. Курсор изменится на символ запрета на отбрасывание (круг с перечеркнутой линией), чтобы указать, что вы не можете отбросить элемент сам по себе.
После запуска события dragstart событие drag запускается постоянно, пока вы перетаскиваете элемент.
И событие dragend срабатывает, когда вы перестаете переносить элемент.
Целью всех событий( e.target ) является перетаскиваемый элемент.
По умолчанию браузер не меняет внешний вид. Таким образом, вы можете настроить его внешний вид в соответствии со своими предпочтениями.
События для целей перетаскивания
Когда вы перетаскиваете элемент по допустимой цели, эти события срабатывают в следующей последовательности:
dragenterdragoverdragleaveилиdrop
Событие dragenter срабатывает, как только вы перетаскиваете элемент на цель.
После того, как событие dragenter срабатывает, событие dragover срабатывает постоянно, пока вы перетаскиваете элемент в пределах границы целевого объекта.
Когда вы перетаскиваете элемент за границу целевого объекта dragover перестает запускаться и dragleaveстановится событием перетаскивания.
Если вы помещаете элемент в цель, вместо события dragleave запускается событие drop.
Целью( e.target ) dragenter, dragover, dragleave и drop являются элементы цели.
Действительная цель
Почти все элементы поддерживают события перетаскивания ( dragenter, dragover, dragleave и drop ). Однако по умолчанию они не позволяют сбрасывать.
Если вы перетащите элемент на цель перетаскивания, которая не позволяет перетаскивать, событие drop не сработает.
Чтобы превратить элемент в допустимую цель перетаскивания, вы можете переопределить поведение по умолчанию событий dragenter и dragover, вызвав метод event.preventDefault() в соответствующих обработчиках событий.(Дополнительную информацию см. в разделе примеров)
Передача данных с помощью объекта dataTransfer
Для передачи данных в действии перетаскивания используется объект dataTransfer.
Объект dataTransfer является свойством события. Он позволяет передавать данные из перетаскиваемого элемента в цель перетаскивания.
Объект dataTransfer имеет два метода: setData() и getData().
setData() позволяет вам установить данные операции в указанный формат и данные:
dataTransfer.setData(format, data)
Формат может быть text/plain или text/uri-list. И данные могут быть строкой, представляющей данные для добавления к объекту перетаскивания.
Метод getData() извлекает данные, сохраненные методом setData().
getData() принимает один аргумент:
dataTransfer(format)
Формат может быть text/plain или text/uri-list. getData() возвращает строку, сохраненную методом setData(), или пустую строку, если операция перетаскивания не включает данные.
Пример
Мы разработаем следующее простое приложение перетаскивания, чтобы продемонстрировать API перетаскивания JavaScript:
Создайте структуру проекта
- Сначала создайте новую папку с именем
drag-n-drop-basics. Внутри этой папки создайте две подпапки сcssиjs. - Во-вторых, создайте новый файл с именем
app.jsв папкеjs,style.cssв папкеcssиindex.htmlв папкеdrag-n-drop-basics. - В-третьих, поместите ссылку на
style.cssи тег script, который ссылается наapp.js, в файлеindex.htmlследующим образом:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JavaScript - Drag and Drop Demo</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <script src="js/app.js"></script> </body> </html>
Создайте файл index.html
Поместите следующий код в файл index.html :
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>JavaScript - Drag and Drop Demo</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <div class="container"> <h1>JavaScript - Drag and Drop</h1> <div class="drop-targets"> <div class="box"> <div class="item" id="item"> </div> </div> <div class="box"></div> <div class="box"></div> </div> </div> <script src="js/app.js"></script> </body> </html>
В этом файле index.html мы использовали элемент .container для выравнивания заголовка и элемента drop-targets.
Внутри элемента drop-targets мы поместили три элемента div с одинаковым классом box. И мы помещаем еще один элемент div с item класса в первое поле.
Если вы откроете index.html и попытаетесь перетащить желтое поле, вы увидите курсор, указывающий, что вы не можете перетаскивать:

Чтобы сделать элемент перетаскиваемым, вы добавляете свойство draggable со значением true в его HTML-тег следующим образом:
<div class="item" id="item" draggable="true">
Теперь, если вы сохраните index.html, снова откроете его в браузере, вы увидите, что вы можете перетаскивать элемент элемента следующим образом:

Обработка событий
В файле style.css есть класс .hide, скрывающий элемент:
.hide {
display: none;
}В файл app.js вы добавляете следующий код:
// select the item element
const item = document.querySelector('.item');
// attach the dragstart event handler
item.addEventListener('dragstart', dragStart);
// handle the dragstart
function dragStart(e) {
console.log('drag starts...');
}Как это работает:
- Сначала выберите перетаскиваемый элемент с помощью
querySelector(). - Во-вторых, прикрепите обработчик события
dragstartк перетаскиваемому элементу. - В-третьих, определите
dragStart()для обработкиdragstart.
Если вы откроете файл index.html и начнете перетаскивать элемент, вы увидите сообщение о drag starts... в консоли.
В обработчике события dragStart вам нужно сохранить id перетаскиваемого элемента. И вам нужно скрыть это:
function dragStart(e) {
e.dataTransfer.setData('text/plain', e.target.id);
e.target.classList.add('hide');
}Если вы перетащите элемент, вы увидите, что он исчезнет, как только вы начнете перетаскивать.
Чтобы решить эту проблему, вы используете функцию setTimeout() :
function dragStart(e) {
e.dataTransfer.setData('text/plain', e.target.id);
setTimeout(() => {
e.target.classList.add('hide');
}, 0);
}Теперь вы можете перетащить перетаскиваемый элемент из исходного положения:

Обработка событий
В файле style.css также есть класс CSS с именем .drag-over, который превращает стиль границы цели перетаскивания в пунктирную и красную:
.drag-over {
border: dashed 3px red;
}В app.js вам нужно выбрать целевые элементы перетаскивания и обработать dragenter, dragover, dragleave и drop этих элементов:
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => {
box.addEventListener('dragenter', dragEnter)
box.addEventListener('dragover', dragOver);
box.addEventListener('dragleave', dragLeave);
box.addEventListener('drop', drop);
});
function dragEnter(e) {
}
function dragOver(e) {
}
function dragLeave(e) {
}
function drop(e) {
}Стиль границы цели перетаскивания должен измениться, когда происходит событие dragenter и dragover. Стиль должен восстанавливаться при возникновении события dragleave and drop.
Для этого вы добавляете и удаляете класс drag-over в цель drop следующим образом:
function dragEnter(e) {
e.target.classList.add('drag-over');
}
function dragOver(e) {
e.target.classList.add('drag-over');
}
function dragLeave(e) {
e.target.classList.remove('drag-over');
}
function drop(e) {
e.target.classList.remove('drag-over');
}Теперь, если вы перетащите перетаскиваемый элемент на другую цель перетаскивания, вы увидите, что граница цели изменится, как показано на следующем рисунке:

Чтобы сделать цель перетаскивания действительной, вам нужно вызвать event.preventDefault() в обработчиках событий dragenter и dragover следующим образом:
function dragEnter(e) {
e.preventDefault();
e.target.classList.add('drag-over');
}
function dragOver(e) {
e.preventDefault();
e.target.classList.add('drag-over');
}Если вы этого не сделаете, событие drop никогда не сработает, потому что элемент div по умолчанию не является допустимой целью перетаскивания.
Если вы перетащите элемент в цель перетаскивания, вы увидите, что курсор изменится, указывая на то, что вы можете перетащить элемент:

Теперь, если вы отбросите элемент, вы увидите, что он немедленно исчезает.
Чтобы решить эту проблему, вам нужно добавить дескриптор события drop.
- Сначала получите
idперетаскиваемого элемента с помощью методаgetData()объектаdataTransfer. - Во-вторых, добавьте перетаскиваемый элемент в качестве дочернего элемента целевого элемента перетаскивания.
- В-третьих, удалите класс
hideизdraggableэлемента.
В следующем коде показан полный обработчик события drop в JavaScript:
function drop(e) {
e.target.classList.remove('drag-over');
// get the draggable element
const id = e.dataTransfer.getData('text/plain');
const draggable = document.getElementById(id);
// add it to the drop target
e.target.appendChild(draggable);
// display the draggable element
draggable.classList.remove('hide');
}Если вы перетащите перетаскиваемый элемент сейчас, он должен работать должным образом.
Ниже показан полный файл app.js:
/* draggable element */
const item = document.querySelector('.item');
item.addEventListener('dragstart', dragStart);
function dragStart(e) {
e.dataTransfer.setData('text/plain', e.target.id);
setTimeout(() => {
e.target.classList.add('hide');
}, 0);
}
/* drop targets */
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => {
box.addEventListener('dragenter', dragEnter)
box.addEventListener('dragover', dragOver);
box.addEventListener('dragleave', dragLeave);
box.addEventListener('drop', drop);
});
function dragEnter(e) {
e.preventDefault();
e.target.classList.add('drag-over');
}
function dragOver(e) {
e.preventDefault();
e.target.classList.add('drag-over');
}
function dragLeave(e) {
e.target.classList.remove('drag-over');
}
function drop(e) {
e.target.classList.remove('drag-over');
// get the draggable element
const id = e.dataTransfer.getData('text/plain');
const draggable = document.getElementById(id);
// add it to the drop target
e.target.appendChild(draggable);
// display the draggable element
draggable.classList.remove('hide');
}Заключение
- Добавьте свойство
draggableсо значением true к элементу, чтобы сделать его перетаскиваемым в JavaScript. - События
dragstart,dragиdragendсрабатывают на перетаскиваемом элементе. - События
dragenter,dragover,dragleaveилиdropсрабатывают на цели. - Вызовите
event.preventDefault()в обработчиках событийdragenterиdragover, чтобы сделать элемент допустимой целью перетаскивания. - Используйте объект
event.dataTransferс методамиsetData()иgetData()для передачи данных в операции.
