Внести вклад
Подробные руководства

Перетаскивание (drag and drop)

Обзор

На этой странице описаны директивы drag and drop, которые позволяют быстро создавать интерфейсы перетаскивания со следующими возможностями:

  • Свободное перетаскивание
  • Создание списка переупорядочиваемых перетаскиваемых элементов
  • Перенос перетаскиваемых элементов между списками
  • Анимации перетаскивания
  • Блокировка перетаскиваемых элементов по оси или внутри элемента
  • Добавление пользовательских ручек перетаскивания
  • Добавление превью при перетаскивании
  • Добавление пользовательского placeholder при перетаскивании

Полный справочник API см. на странице справочника API drag and drop Angular CDK.

Перед началом

Установка CDK

Component Dev Kit (CDK) — набор примитивов поведения для создания компонентов. Чтобы использовать директивы drag and drop, сначала установите @angular/cdk из npm. Это можно сделать из терминала с помощью Angular CLI:

ng add @angular/cdk

Импорт drag and drop

Чтобы использовать drag and drop, импортируйте необходимое из директив в компонент.

import {Component} from '@angular/core';
import {CdkDrag} from '@angular/cdk/drag-drop';

@Component({
  selector: 'drag-drop-example',
  templateUrl: 'drag-drop-example.html',
  imports: [CdkDrag],
})
export class DragDropExample {}

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

Любой элемент можно сделать перетаскиваемым, добавив директиву cdkDrag. По умолчанию все перетаскиваемые элементы поддерживают свободное перетаскивание.

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

Добавьте директиву cdkDropList к родительскому элементу, чтобы сгруппировать перетаскиваемые элементы в переупорядочиваемую коллекцию. Это определяет, куда можно сбрасывать перетаскиваемые элементы. Перетаскиваемые элементы в группе drop list автоматически перестраиваются при перемещении элемента.

Директивы drag and drop не обновляют модель данных. Чтобы обновить модель данных, подпишитесь на событие cdkDropListDropped (после того как пользователь завершит перетаскивание) и обновите модель данных вручную.

Можно использовать injection token CDK_DROP_LIST, который позволяет ссылаться на экземпляры cdkDropList. Подробнее см. руководство по внедрению зависимостей и API injection token drop list.

Перенос перетаскиваемых элементов между списками

Директива cdkDropList поддерживает перенос перетаскиваемых элементов между связанными drop list. Есть два способа связать один или несколько экземпляров cdkDropList:

  • Установить свойство cdkDropListConnectedTo на другой drop list.
  • Обернуть элементы в элемент с атрибутом cdkDropListGroup.

Директива cdkDropListConnectedTo работает как с прямой ссылкой на другой cdkDropList, так и со ссылкой на id другого drop-контейнера.

<!-- This is valid -->
<div cdkDropList #listOne="cdkDropList" [cdkDropListConnectedTo]="[listTwo]"></div>
<div cdkDropList #listTwo="cdkDropList" [cdkDropListConnectedTo]="[listOne]"></div>

<!-- This is valid as well -->
<div cdkDropList id="list-one" [cdkDropListConnectedTo]="['list-two']"></div>
<div cdkDropList id="list-two" [cdkDropListConnectedTo]="['list-one']"></div>

Используйте директиву cdkDropListGroup, если у вас неизвестное количество связанных drop list — она автоматически настраивает соединение. Любой новый cdkDropList, добавленный в группу, автоматически связывается со всеми остальными списками.

<div cdkDropListGroup>
  <!-- All lists in here will be connected. -->
  @for (list of lists; track list) {
    <div cdkDropList></div>
  }
</div>

Можно использовать injection token CDK_DROP_LIST_GROUP, который позволяет ссылаться на экземпляры cdkDropListGroup. Подробнее см. руководство по внедрению зависимостей и API injection token drop list group.

Выборочное перетаскивание

По умолчанию пользователь может перемещать элементы cdkDrag из одного контейнера в другой связанный контейнер. Для более точного контроля над тем, какие элементы можно сбрасывать в контейнер, используйте cdkDropListEnterPredicate. Angular вызывает предикат всякий раз, когда перетаскиваемый элемент входит в новый контейнер. В зависимости от того, возвращает предикат true или false, элемент может быть разрешён или запрещён в новый контейнер.

Привязка данных

Можно связать произвольные данные как с cdkDrag, так и с cdkDropList, установив соответственно cdkDragData или cdkDropListData. Можно подписаться на события, генерируемые обеими директивами, которые будут включать эти данные, что позволяет легко определить источник взаимодействия drag или drop.

@for (list of lists; track list) {
  <div cdkDropList [cdkDropListData]="list" (cdkDropListDropped)="drop($event)">
    @for (item of list; track item) {
      <div cdkDrag [cdkDragData]="item"></div>
    }
  </div>
}

Настройка перетаскивания

Настройка ручки перетаскивания

По умолчанию пользователь может перетаскивать весь элемент cdkDrag. Чтобы ограничить перетаскивание только через элемент-ручку, добавьте директиву cdkDragHandle к элементу внутри cdkDrag. Можно иметь сколько угодно элементов cdkDragHandle.

Можно использовать injection token CDK_DRAG_HANDLE, который позволяет ссылаться на экземпляры cdkDragHandle. Подробнее см. руководство по внедрению зависимостей и API injection token drag handle.

Настройка превью перетаскивания

Элемент превью становится видимым, когда элемент cdkDrag перетаскивается. По умолчанию превью — это клон оригинального элемента, расположенный рядом с курсором пользователя.

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

У клонированного элемента удаляется атрибут id, чтобы избежать нескольких элементов с одинаковым id на странице. Из-за этого CSS, нацеленный на этот id, не будет применён.

Можно использовать injection token CDK_DRAG_PREVIEW, который позволяет ссылаться на экземпляры cdkDragPreview. Подробнее см. руководство по внедрению зависимостей и API injection token drag preview.

Настройка точки вставки при перетаскивании

По умолчанию Angular вставляет превью cdkDrag в <body> страницы, чтобы избежать проблем с позиционированием и overflow. В некоторых случаях это может быть нежелательно, поскольку превью не получит унаследованные стили.

Можно изменить место вставки превью с помощью входа cdkDragPreviewContainer на cdkDrag. Возможные значения:

Значение Описание Преимущества Недостатки
global Значение по умолчанию. Angular вставляет превью в <body> или ближайший shadow root. Превью не зависит от z-index и overflow: hidden. Также не влияет на селекторы :nth-child и flex-раскладки. Не сохраняет унаследованные стили.
parent Angular вставляет превью внутрь родителя перетаскиваемого элемента. Превью наследует те же стили, что и перетаскиваемый элемент. Превью может быть обрезано из‑за overflow: hidden или оказаться под другими элементами из‑за z-index. Также может влиять на селекторы :nth-child и некоторые flex-раскладки.
ElementRef или HTMLElement Angular вставляет превью в указанный элемент. Превью наследует стили от указанного контейнера. Превью может быть обрезано из‑за overflow: hidden или оказаться под другими элементами из‑за z-index. Также может влиять на селекторы :nth-child и некоторые flex-раскладки.

Альтернативно можно изменить injection token CDK_DRAG_CONFIG, чтобы обновить previewContainer в конфигурации, если значение — global или parent. Подробнее см. руководство по внедрению зависимостей, API injection token drag config и API drag drop config.

Настройка placeholder перетаскивания

Пока элемент cdkDrag перетаскивается, директива создаёт элемент placeholder, показывающий, куда элемент будет помещён при сбросе. По умолчанию placeholder — это клон перетаскиваемого элемента. Можно заменить placeholder пользовательским с помощью директивы *cdkDragPlaceholder:

Можно использовать injection token CDK_DRAG_PLACEHOLDER, который позволяет ссылаться на экземпляры cdkDragPlaceholder. Подробнее см. руководство по внедрению зависимостей и API injection token drag placeholder.

Настройка корневого элемента перетаскивания

Установите атрибут cdkDragRootElement, если есть элемент, который нужно сделать перетаскиваемым, но у вас нет прямого доступа к нему.

Атрибут принимает селектор и просматривает DOM, пока не найдёт элемент, соответствующий селектору. Если элемент найден, он становится перетаскиваемым. Это полезно, например, для перетаскивания диалогового окна.

Альтернативно можно изменить injection token CDK_DRAG_CONFIG, чтобы обновить rootElementSelector в конфигурации. Подробнее см. руководство по внедрению зависимостей, API injection token drag config и API drag drop config.

Установка DOM-позиции перетаскиваемого элемента

По умолчанию элементы cdkDrag, не находящиеся в cdkDropList, перемещаются из обычной DOM-позиции только когда пользователь вручную перемещает элемент. Используйте вход cdkDragFreeDragPosition, чтобы явно задать позицию элемента. Типичный случай — восстановление позиции перетаскиваемого элемента после того, как пользователь ушёл со страницы и вернулся.

Ограничение перемещения внутри элемента

Чтобы запретить пользователю перетаскивать элемент cdkDrag за пределы другого элемента, передайте CSS-селектор в атрибут cdkDragBoundary. Атрибут принимает селектор и просматривает DOM, пока не найдёт соответствующий элемент. Если совпадение найдено, элемент становится границей, за которую перетаскиваемый элемент не может выйти. cdkDragBoundary также можно использовать, когда cdkDrag размещён внутри cdkDropList.

Альтернативно можно изменить injection token CDK_DRAG_CONFIG, чтобы обновить boundaryElement в конфигурации. Подробнее см. руководство по внедрению зависимостей, API injection token drag config и API drag drop config.

Ограничение перемещения по оси

По умолчанию cdkDrag позволяет свободное перемещение во всех направлениях. Чтобы ограничить перетаскивание по определённой оси, установите cdkDragLockAxis в «x» или «y» на cdkDrag. Чтобы ограничить перетаскивание для нескольких перетаскиваемых элементов внутри cdkDropList, установите cdkDropListLockAxis на cdkDropList.

Альтернативно можно изменить injection token CDK_DRAG_CONFIG, чтобы обновить lockAxis в конфигурации. Подробнее см. руководство по внедрению зависимостей, API injection token drag config и API drag drop config.

Задержка перетаскивания

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

Можно задержать последовательность перетаскивания с помощью входа cdkDragStartDelay. Вход ожидает, пока пользователь удерживает указатель заданное количество миллисекунд, прежде чем начать перетаскивание элемента.

Альтернативно можно изменить injection token CDK_DRAG_CONFIG, чтобы обновить dragStartDelay в конфигурации. Подробнее см. руководство по внедрению зависимостей, API injection token drag config и API drag drop config.

Отключение перетаскивания

Чтобы отключить перетаскивание для конкретного элемента, установите вход cdkDragDisabled на элементе cdkDrag в true или false. Можно отключить весь список с помощью входа cdkDropListDisabled на cdkDropList. Также можно отключить конкретную ручку через cdkDragHandleDisabled на cdkDragHandle.

Альтернативно можно изменить injection token CDK_DRAG_CONFIG, чтобы обновить draggingDisabled в конфигурации. Подробнее см. руководство по внедрению зависимостей, API injection token drag config и API drag drop config.

Настройка сортировки

Ориентация списка

По умолчанию директива cdkDropList предполагает вертикальные списки. Это можно изменить, установив свойство cdkDropListOrientation в horizontal.

Альтернативно можно изменить injection token CDK_DRAG_CONFIG, чтобы обновить listOrientation в конфигурации. Подробнее см. руководство по внедрению зависимостей, API injection token drag config и API drag drop config.

Перенос строк в списке

По умолчанию cdkDropList сортирует перетаскиваемые элементы, перемещая их с помощью CSS transform. Это позволяет анимировать сортировку, что улучшает пользовательский опыт. Однако drop list работает только в одном направлении: вертикально или горизонтально.

Если у вас сортируемый список, который должен переноситься на новые строки, установите атрибут cdkDropListOrientation в mixed. Это заставляет список использовать другую стратегию сортировки элементов — перемещение в DOM. Однако список больше не может анимировать действие сортировки.

Выборочная сортировка

По умолчанию элементы cdkDrag сортируются в любую позицию внутри cdkDropList. Чтобы изменить это поведение, установите атрибут cdkDropListSortPredicate, который принимает функцию. Функция-предикат вызывается, когда перетаскиваемый элемент собирается переместиться на новый индекс в drop list. Если предикат возвращает true, элемент перемещается на новый индекс, иначе остаётся на текущей позиции.

Отключение сортировки

Бывают случаи, когда перетаскиваемые элементы можно перетащить из одного cdkDropList в другой, но пользователь не должен иметь возможность сортировать их внутри исходного списка. Для таких случаев добавьте атрибут cdkDropListSortingDisabled, чтобы запретить сортировку перетаскиваемых элементов в cdkDropList. Это сохраняет начальную позицию перетаскиваемого элемента в исходном списке, если он не перетащен на новую допустимую позицию.

Альтернативно можно изменить injection token CDK_DRAG_CONFIG, чтобы обновить sortingDisabled в конфигурации. Подробнее см. руководство по внедрению зависимостей, API injection token drag config и API drag drop config.

Копирование элементов между списками

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

Чтобы включить копирование, установите вход cdkDropListHasAnchor. Это указывает cdkDropList создать «якорный» элемент, который остаётся в исходном контейнере и не перемещается вместе с элементом. Если пользователь вернёт элемент в исходный контейнер, якорь удаляется автоматически. Якорный элемент можно стилизовать, нацелившись на CSS-класс .cdk-drag-anchor.

Сочетание cdkDropListHasAnchor с cdkDropListSortingDisabled позволяет создать список, из которого пользователь может копировать элементы, не имея возможности переупорядочить исходный список (например, список товаров и корзина покупок).

Настройка анимаций

Перетаскивание поддерживает анимации для:

  • Сортировки перетаскиваемого элемента внутри списка
  • Перемещения перетаскиваемого элемента из позиции, куда пользователь его сбросил, в финальную позицию внутри списка

Чтобы настроить анимации, определите CSS-переход, нацеленный на свойство transform. Для анимаций можно использовать следующие классы:

Имя CSS-класса Результат добавления перехода
.cdk-drag Анимирует перетаскиваемые элементы во время сортировки.
.cdk-drag-animating Анимирует перетаскиваемый элемент от позиции сброса до финальной позиции внутри cdkDropList.

Этот CSS-класс применяется к элементу cdkDrag только после завершения действия перетаскивания.

Стилизация

Директивы cdkDrag и cdkDropList применяют только необходимые стили для функциональности. Приложения могут настраивать стили, нацеливаясь на указанные CSS-классы.

Имя CSS-класса Описание
.cdk-drop-list Селектор контейнеров cdkDropList.
.cdk-drag Селектор элементов cdkDrag.
.cdk-drag-disabled Селектор отключённых элементов cdkDrag.
.cdk-drag-handle Селектор host-элемента cdkDragHandle.
.cdk-drag-preview Селектор элемента превью перетаскивания. Это элемент, который появляется рядом с курсором, пока пользователь перетаскивает элемент в сортируемом списке.

Элемент выглядит так же, как перетаскиваемый, если не настроен пользовательский шаблон через *cdkDragPreview.
.cdk-drag-placeholder Селектор элемента placeholder. Это элемент, который отображается в месте, куда будет помещён перетаскиваемый элемент после завершения перетаскивания.

Элемент выглядит так же, как сортируемый, если не настроен через директиву cdkDragPlaceholder.
.cdk-drop-list-dragging Селектор контейнера cdkDropList, в котором сейчас перетаскивается элемент.
.cdk-drop-list-disabled Селектор отключённых контейнеров cdkDropList.
.cdk-drop-list-receiving Селектор контейнера cdkDropList, который может принять перетаскиваемый элемент из связанного списка сброса, пока тот перетаскивается.
.cdk-drag-anchor Селектор якорного элемента, создаваемого при включённом cdkDropListHasAnchor. Этот элемент указывает позицию, с которой началось перетаскивание.

Перетаскивание в прокручиваемом контейнере

Если перетаскиваемые элементы находятся внутри прокручиваемого контейнера (например, div с overflow: auto), автоматическая прокрутка не будет работать, пока прокручиваемый контейнер не имеет директивы cdkScrollable. Без неё CDK не может обнаружить или управлять поведением прокрутки контейнера во время операций перетаскивания.

Интеграция с другими компонентами

Функциональность drag-and-drop CDK может интегрироваться с различными компонентами. Типичные случаи — сортируемые компоненты MatTable и сортируемые компоненты MatTabGroup.