Drag and Drop API в JavaScript: перетаскивание элементов на примерах

В этом руководстве вы узнаете об API Drag and Drop в JavaScript и о том, как использовать его для реализации простого приложения перетаскивания элементов.

HTML5 официально представил спецификацию перетаскивания. В большинстве современных веб-браузеров реализовано собственное перетаскивание на основе спецификации HTML5.

По умолчанию можно перетаскивать только изображение и текст. Чтобы перетащить изображение, просто нажмите и удерживайте кнопку мыши, а затем переместите его. Чтобы перетащить текст, вам нужно выделить текст и перетащить его так же, как перетаскивание изображения.

Спецификация HTML5 указывает, что почти все элементы можно перетаскивать. Чтобы сделать элемент перетаскиваемым, вы добавляете свойство draggable со значением true в его HTML-тег. Например:

<div class="item" draggable="true"></div>

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

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

  • dragstart
  • drag
  • dragend

Когда вы удерживаете кнопку мыши и начинаете двигать мышь, событие dragstart срабатывает на перетаскиваемом элементе. Курсор изменится на символ запрета на отбрасывание (круг с перечеркнутой линией), чтобы указать, что вы не можете отбросить элемент сам по себе.

После запуска события dragstart событие drag запускается постоянно, пока вы перетаскиваете элемент.

И событие dragend срабатывает, когда вы перестаете переносить элемент.

Целью всех событий( e.target ) является перетаскиваемый элемент.

По умолчанию браузер не меняет внешний вид. Таким образом, вы можете настроить его внешний вид в соответствии со своими предпочтениями.

События для целей перетаскивания

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

  • dragenter
  • dragover
  • dragleave или 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, снова откроете его в браузере, вы увидите, что вы можете перетаскивать элемент элемента следующим образом:

Сохраните 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() для передачи данных в операции.
Рейтинг
( Пока оценок нет )
Александр Русаков / автор статьи
Программист, разработчик, 12 лет опыта работы в крупных компаниях. Быстро освоил typescript, делюсь своими знаниями на страницах этого сайта.
Загрузка ...
JavaScript и TypeScript