Практическая сортировка списка перетаскиванием
Создайте список с изменяемым порядком с помощью API перетаскивания
«Практическая сортировка списка перетаскиванием» — бесплатный урок HTML Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения HTML Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс HTML Academy содержит 4 уроков всего.
Обзор шаблона
Чтобы создать список с изменением порядка элементов перетаскиванием, сделайте каждый элемент перетаскиваемым, сохраните идентификатор перетаскиваемого элемента в dataTransfer при dragstart, а при сбросе вставьте перетаскиваемый элемент перед целью или после неё. DOM и модель останутся синхронизированными, если после каждого сброса заново строить порядок на основе DOM.
Разметка
Отобразите плоский список, в котором каждый li содержит draggable="true" и data-id. Если идентификаторы хранятся в самих элементах, обработчикам перетаскивания не нужно обращаться к отдельному хранилищу состояния, чтобы определить элементы: источником истины служит сам элемент.
<ul id="list">
<li draggable="true" data-id="1">Item 1</li>
<li draggable="true" data-id="2">Item 2</li>
<li draggable="true" data-id="3">Item 3</li>
</ul>dragstart записывает источник
При dragstart сохраните идентификатор перетаскиваемого элемента в dataTransfer и добавьте класс "dragging" для визуальной обратной связи. effectAllowed="move" сообщает браузеру, что выполняется изменение порядка, а не копирование, поэтому курсор и dropEffect отражают операцию перемещения.
list.addEventListener("dragstart", (e) => {
const li = e.target.closest("li");
if (!li) return;
e.dataTransfer.setData("text/plain", li.dataset.id);
e.dataTransfer.effectAllowed = "move";
li.classList.add("dragging");
});dragover разрешает сброс
Установите обработчик на списке (делегирование событий), вызовите preventDefault и задайте для dropEffect значение "move". Используйте e.target.closest("li"), чтобы найти строку, над которой находится курсор: один и тот же обработчик будет работать для всего списка.
Вычисление позиции вставки
Чтобы определить, должен ли перетаскиваемый элемент оказаться над строкой, на которую наведён курсор, или под ней, сравните координату Y курсора с вертикальной серединой строки: const before = (e.clientY - rect.top) < rect.height / 2. before=true означает вставку с помощью insertBefore, а before=false — с помощью insertAfter.
function getInsertBefore(target, clientY) {
const rect = target.getBoundingClientRect();
return clientY < rect.top + rect.height / 2;
}drop изменяет порядок в DOM
В обработчике drop найдите перетаскиваемый элемент по идентификатору и строку, на которую указывает курсор. Вызовите list.insertBefore(dragged, target) или list.insertBefore(dragged, target.nextSibling) в зависимости от того, на какую половину цели наведён курсор.
dragend очищает стили
Независимо от того, успешно ли выполнен сброс или пользователь нажал Escape, источник всегда получает событие dragend. Используйте его, чтобы удалить класс "dragging" и все подсветки целей сброса, возвращая список в состояние ожидания.
list.addEventListener("dragend", () => {
list.querySelectorAll(".dragging, .over").forEach((el) => {
el.classList.remove("dragging", "over");
});
});Визуальный индикатор сброса
Показывайте тонкую линию в месте, куда будет помещён элемент, используя псевдоэлемент CSS для строки, на которую наведён курсор. Переключайте её с помощью класса "over-top" или "over-bottom", который обработчик dragover задаёт на основе положения курсора. Пользователь видит точку вставки ещё до отпускания кнопки.
Синхронизация модели
После сброса получите новый порядок из DOM: const order = Array.from(list.children).map((li) => li.dataset.id). Отправьте этот массив на сервер или сохраните его в состоянии — никогда не пытайтесь поддерживать параллельный индекс рядом с DOM, поскольку при быстрых перетаскиваниях они расходятся.
Клавиатурная альтернатива
Добавьте обработчики Up/Down, которые перемещают сфокусированный элемент с помощью insertBefore. Сообщайте о перемещении через область aria-live ("Элемент перемещён вверх на позицию 2"). Пользователи клавиатуры получают ту же возможность без использования визуального перетаскивания, что крайне важно для доступности.
Альтернатива для сенсорных устройств
На мобильных устройствах замените встроенное перетаскивание на Pointer Events: при pointerdown захватите строку, при pointermove перемещайте её с помощью CSS transform, а при pointerup определите строку под ней и измените порядок. Библиотеки вроде SortableJS инкапсулируют этот шаблон для разных типов ввода.
Проверка знаний
Почему мы вычисляем позицию вставки по положению курсора относительно вертикальной середины строки, на которую он наведён?
Итоги
Надёжный список с изменением порядка объединяет draggable="true" + dragstart (запись идентификатора, effectAllowed=move) + dragover (preventDefault + положение индикатора) + drop (insertBefore в позицию, определённую относительно середины) + dragend (очистка). Всегда получайте новый порядок из DOM после сброса и добавляйте клавиатурную альтернативу для доступности.
Часто задаваемые вопросы
Урок «Практическая сортировка списка перетаскиванием» бесплатный?
Да — полный текст урока «Практическая сортировка списка перетаскиванием» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс HTML Academy, подпишись на CoddyKit PRO. Курс HTML Academy содержит 4 уроков всего.
Чему я научусь в уроке «Практическая сортировка списка перетаскиванием»?
Создайте список с изменяемым порядком с помощью API перетаскивания Ты практикуешь HTML Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать HTML Academy?
Предыдущий опыт не требуется. HTML Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Практическая сортировка списка перетаскиванием»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке HTML Academy?
Да. Каждый урок HTML Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Атрибут draggable и событие dragstart
- События dragover и drop
- Объект dataTransfer
- Практическая сортировка списка перетаскиванием