Перетаскиваемые элементы на VanillaJS и HTML

Перетаскивание – это одно из самых распространенных пользовательских взаимодействий с контентом, оно встречается во многих графических интерфейсах.

Для добавления функции перетаскивания в ваше приложение существуют предварительно подготовленные библиотеки JavaScript. Однако в некоторых ситуациях такие библиотеки невозможно или очень дорого использовать (к примеру, это требует больше ресурсов или вводит зависимости, которые не нужны вашему проекту). В подобных случаях вам пригодится знание API-интерфейсов, доступных в современных веб-браузерах – с их помощью вы можете найти альтернативные решения.

HTML Drag and Drop API использует модель событий DOM для получения данных о перетаскиваемых элементах и для их обновления. По сути, с помощью обработчиков событий JavaScript вы можете превратить любой элемент в перетаскиваемый.

В этом руководстве мы создадим простые перетаскиваемые элементы на основе обработчиков событий с помощью API Drag and Drop и ванильного JavaScript.

Требования

Для выполнения этого туториала вам понадобится современный веб-браузер, поддерживающий Drag and Drop API: это может быть Chrome 4+, Firefox 3.5+, Safari 3.1+, Edge 18+.

1: Создание проекта и базовая разметка

Наш тестовый проект будет состоять из контейнера с двумя типами дочерних элементов:

  1. Дочерние элементы, которые можно перетаскивать.
  2. Дочерние элементы, в которые можно поместить/перетащить элементы.

Сначала откройте окно терминала и создайте новый каталог для нашего тестового проекта:

mkdir drag-and-drop-example

Перейдите в этот каталог:

cd drag-and-drop-example

Далее нужно создать файл index.html:

nano index.html

Затем вставьте в этот файл шаблонный код для веб-страницы HTML:

<!DOCTYPE html>
<html>
<head>
<title>My Drag-and-Drop Example</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
</body>
</html>

В теги <body> поместите draggable (перетаскиваемый элемент) и dropzone (зону перетаскивания):

<div class="example-parent">
<div class="example-origin">
<div
id="draggable-1"
class="example-draggable"
>
draggable
</div>
</div>
<div
class="example-dropzone"
>
dropzone
</div>
</div>

Сохраните и закройте файл. Затем создайте файл style.css:

nano style.css

Поместите в этот файл стили для элементов, которые мы создали в файле index.html:

.example-parent {
border: 2px solid #DFA612;
color: black;
display: flex;
font-family: sans-serif;
font-weight: bold;
}
.example-origin {
flex-basis: 100%;
flex-grow: 1;
padding: 10px;
}
.example-draggable {
background-color: #4AAE9B;
font-weight: normal;
margin-bottom: 10px;
margin-top: 10px;
padding: 10px;
}
.example-dropzone {
background-color: #6DB65B;
flex-basis: 100%;
flex-grow: 1;
padding: 10px;
}

Этот файл содержит оформление нашего тестового приложения. Теперь вы можете просмотреть index.html в браузере. Вы должны увидеть элементы draggable <div> и dropzone <div>.

После этого мы явно сделаем первый <div> перетаскиваемым, для этого нужно добавить атрибут draggable в файл index.html:

<div class="example-parent">
<div class="example-origin">
<div
id="draggable-1"
class="example-draggable"
draggable="true"
>
draggable
</div>
</div>
<div
class="example-dropzone"
>
dropzone
</div>
</div>

Сохраните и закройте файл.

Снова просмотрите index.html в браузере. Если вы кликнете на draggable <div> и перетащите его по экрану, то его перемещение будет визуализировано.

Значение атрибута draggable по умолчанию – auto. Следовательно, возможность перетаскивать элементы будет определяться поведением вашего браузера по умолчанию. Как правило, это означает, что выделенный текст, изображения и ссылки можно перетаскивать без значения draggable=”true”.

Итак, у вас есть HTML-файл с перетаскиваемым элементом. Перейдем к созданию обработчиков событий.

2: Обработка событий с помощью JavaScript

Если на данный момент мы отпустим мышь при перетаскивании элемента, ничего не произойдет. Чтобы при перетаскивании элементов DOM вызывалось действие, нужно использовать Drag and Drop API:

  • ondragstart: это обработчик событий, который будет прикреплен к перетаскиваемому элементу. Он срабатывает при возникновении события dragstart.
  • ondragover: обработчик событий, который будет прикреплен к элементу dropzone и сработает при возникновении события dragover.
  • ondrop: этот обработчик также будет прикреплен к элементу dropzone. Он сработает при возникновении события drop.

Примечание: Всего существует восемь обработчиков событий: ondrag, ondragend, ondragenter, ondragexit, ondragleave, ondragover, ondragstart и ondrop. Но в нашем примере мы не будем использовать их все.

Во-первых, добавим в index.html ссылку на новый файл script.js:

<body>
...
<script src="script.js"></script>
</body>

Во-вторых, создадим этот файл:

nano script.js

Объект DataTransfer будет отслеживать информацию, относящуюся к текущему событию перетаскивания. Чтобы обновить элемент при перетаскивании, нам нужен прямой доступ к объекту DataTransfer. Для этого можно выбрать свойство dataTransfer в DragEvent элемента DOM.

Примечание: Технически объект DataTransfer может отслеживать информацию по нескольким элементам, которые перетаскиваются одновременно. Однако в нашем примере мы сосредоточимся на перетаскивании одного элемента.

Метод setData объекта dataTransfer можно использовать для установки информации о состоянии текущего перетаскиваемого элемента. Этот метод принимает два параметра:

  • строка, которая объявляет формат второго параметра
  • фактические передаваемые данные

Наша цель – переместить перетаскиваемый элемент draggable в новый родительский элемент. Поэтому нам нужно иметь возможность выбирать перетаскиваемый элемент по уникальному идентификатору. Установить id перетаскиваемого элемента можно с помощью метода setData (его можно будет использовать позже).

Вернемся к нашему файлу script.js и поместим в него новую функцию для использования метода setData:

function onDragStart(event) {
event
.dataTransfer
.setData('text/plain', event.target.id);
}

Примечание: В Internet Explorer 9–11 при использовании ‘text/plain’ возникают проблемы. Если вы пользуетесь этим браузером, укажите формат ‘text’.

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

Давайте вернемся в файл script.js, расширим нашу функцию и установим в параметре backgroundColor значение yellow:

function onDragStart(event) {
event
.dataTransfer
.setData('text/plain', event.target.id);
event
.currentTarget
.style
.backgroundColor = 'yellow';
}

Примечание: Любые изменяемые при перетаскивании стили нужно будет обновить вручную, если вы хотите использовать эти стили только на время перетаскивания. Значит, если вы измените что-либо в начале перетаскивания, перемещаемый элемент сохранит этот новый стиль, пока вы сами не измените его.

Теперь у нас есть функция JavaScript для начала события перетаскивания.

Мы можем добавить ondragstart к элементу draggable в файле index.html:

<div class="example-parent">
<div class="example-origin">
<div
id="draggable-1"
class="example-draggable"
draggable="true"
ondragstart="onDragStart(event);"
>
draggable
</div>
</div>
<div class="example-dropzone">
dropzone
</div>
</div>

Просмотрите index.html в своем браузере. Если вы попытаетесь перетащить свой элемент, к нему будет применен объявленный в нашей функции стиль.

Однако, когда вы отпустите кнопку мыши, все еще ничего не произойдет.

Следующий обработчик события в этой последовательности – ondragover.

Стандартное поведение определенных элементов DOM (среди которых <div>) в браузерах обычно не позволяет оставить перетаскиваемый элемент в новом месте. Следовательно, это поведение перехватит и заменит то поведение, которое мы пытаемся реализовать. Чтобы обеспечить желаемое поведение при отпускании кнопки мыши, мы применим preventDefault.

Давайте вернемся в script.js и создадим новую функцию для preventDefault. Добавьте такой код в конец файла:

function onDragOver(event) {
event.preventDefault();
}

Теперь мы можем добавить обработчик ondragover к нашему элементу dropzone в файле index.html:

<div class="example-parent">
<div class="example-origin">
<div
id="draggable-1"
class="example-draggable"
draggable="true"
ondragstart="onDragStart(event);"
>
draggable
</div>
</div>
<div
class="example-dropzone"
ondragover="onDragOver(event);"
>
dropzone
</div>
</div>

На данный момент мы еще не написали код, фактически обрабатывающий возможность оставить перемещенный элемент в новом месте. Для этого нужен последний обработчик событий, запускаемый в этой последовательности, – ondrop.

Вернемся к нашему файлу script.js и создадим новую функцию.

Мы можем ссылаться на данные, которые сохранили ранее, с помощью метода setData объекта dataTransfer. Давайте используем метод getData объекта dataTransfer. Здесь мы установили id, поэтому мы получим следующие данные:

function onDrop(event) {
const id = event
.dataTransfer
.getData('text');
}

В файле script.js выберите элемент draggable с извлеченным id:

function onDrop(event) {
// ...
const draggableElement = document.getElementById(id);
}

Далее выберем элемент dropzone:

function onDrop(event) {
// ...
const dropzone = event.target;
}

После чего мы добавим элемент draggable в dropzone:

function onDrop(event) {
// ...
dropzone.appendChild(draggableElement);
}

Сбросьте объект dataTransfer:

function onDrop(event) {
// ...
event
.dataTransfer
.clearData();
}

Теперь мы можем добавить обработчик ondrop к элементу dropzone в файле index.html:

<div class="example-parent">
<div class="example-origin">
<div
id="draggable-1"
class="example-draggable"
draggable="true"
ondragstart="onDragStart(event);"
>
draggable
</div>
</div>
<div
class="example-dropzone"
ondragover="onDragOver(event);"
ondrop="onDrop(event);"
>
dropzone
</div>
</div>

Как только это будет сделано, наша функция перетаскивания будет полностью готова. Обновите index.html в своем браузере и перетащите элемент draggable в область dropzone.

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

3: Продвинутое использование Drag and Drop API

Здесь мы приведем более сложный пример использования этого API с несколькими перетаскиваемыми элементами.

Предположим, вы хотите создать список дел с перетаскиваемыми задачами, которые вы могли бы переместить из столбца To-do в столбец Done.

Чтобы создать такой список дел, добавьте в index.html больше перетаскиваемых элементов с уникальными id. Например:

<div class="example-parent">
<h1>To-do list</h1>
<div class="example-origin">
To-do
<div
id="draggable-1"
class="example-draggable"
draggable="true"
ondragstart="onDragStart(event);"
>
thing 1
</div>
<div
id="draggable-2"
class="example-draggable"
draggable="true"
ondragstart="onDragStart(event);"
>
thing 2
</div>
<div
id="draggable-3"
class="example-draggable"
draggable="true"
ondragstart="onDragStart(event);"
>
thing 3
</div>
<div
id="draggable-4"
class="example-draggable"
draggable="true"
ondragstart="onDragStart(event);"
>
thing 4
</div>
</div>
<div
class="example-dropzone"
ondragover="onDragOver(event);"
ondrop="onDrop(event);"
>
Done
</div>
</div>

Обновите index.html в браузере и попробуйте перетащить элементы из столбца To-do в столбец Done.

Заключение

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

Drag and Drop API предоставляет множество вариантов пользовательской настройки других действий, кроме перетаскивания. Например, вы можете обновить CSS-стиль перетаскиваемых элементов. Кроме того, вместо перемещения элемента вы можете скопировать перетаскиваемый элемент и реплицировать его при отпускании кнопки мыши.

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

Чтобы узнать больше обо всех возможностях Drag and Drop API, ознакомьтесь с документацией MDN.

Читайте также: Подготовка проекта CSS и HTML с помощью Visual Studio Code

Tags: , , ,

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