Angular CDK предоставляет мощный модуль DragDrop
для реализации функциональности перетаскивания элементов. Рассмотрим полный процесс настройки и использования.
Сначала необходимо импортировать модуль DragDropModule:
import { DragDropModule } from '@angular/cdk/drag-drop';
@NgModule({
imports: [
DragDropModule
]
})
export class AppModule { }
Минимальная реализация для перетаскивания элементов внутри одного списка:
<div cdkDropList class="list" (cdkDropListDropped)="drop($event)">
<div *ngFor="let item of items" cdkDrag class="item">
{{item}}
</div>
</div>
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];
drop(event: CdkDragDrop<string[]>) {
moveItemInArray(this.items, event.previousIndex, event.currentIndex);
}
.list {
width: 200px;
border: 1px solid #ccc;
padding: 10px;
}
.item {
padding: 10px;
margin: 5px 0;
background: #f5f5f5;
cursor: move;
}
Для реализации перетаскивания между разными списками:
<div class="container">
<div cdkDropList #todoList="cdkDropList" [cdkDropListData]="todo"
[cdkDropListConnectedTo]="[doneList]" class="list"
(cdkDropListDropped)="drop($event)">
<div *ngFor="let item of todo" cdkDrag class="item">{{item}}</div>
</div>
<div cdkDropList #doneList="cdkDropList" [cdkDropListData]="done"
[cdkDropListConnectedTo]="[todoList]" class="list"
(cdkDropListDropped)="drop($event)">
<div *ngFor="let item of done" cdkDrag class="item">{{item}}</div>
</div>
</div>
import { transferArrayItem } from '@angular/cdk/drag-drop';
todo = ['Task 1', 'Task 2', 'Task 3'];
done = ['Task 4'];
drop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}
<div cdkDropList [cdkDropListEnterPredicate]="noWeekendsPredicate">
noWeekendsPredicate = (drag: CdkDrag, drop: CdkDropList) => {
return !drag.data.includes('weekend');
}
<div cdkDrag [cdkDragStartDelay]="200">...</div>
<div cdkDrag [cdkDragLockAxis]="'x'">...</div>
Основные события:
cdkDragStarted
- начало перетаскиванияcdkDragReleased
- окончание перетаскиванияcdkDragEntered
- вход в зону dropcdkDragExited
- выход из зоны dropcdkDragDropped
- завершение dropПример использования:
<div cdkDrag (cdkDragStarted)="onDragStart($event)"
(cdkDragEnded)="onDragEnd($event)">
Drag me!
</div>
<div cdkDrag>
<div *cdkDragPreview>{{item.name}}</div>
<div class="item-content">{{item.name}}</div>
</div>
<div cdkDropList>
<div *cdkDragPlaceholder class="placeholder"></div>
<div *ngFor="let item of items" cdkDrag>{{item}}</div>
</div>
.placeholder {
background: #ccc;
border: dotted 3px #999;
min-height: 60px;
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
Пример с объектами:
items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' }
];
drop(event: CdkDragDrop<any[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}
trackBy
с *ngFor
:<div *ngFor="let item of items; trackBy: trackById" cdkDrag>
trackById(index: number, item: any): number {
return item.id;
}
OnPush
:@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
Для работы с реактивными формами:
this.form = this.fb.group({
items: this.fb.array(this.items.map(item => this.fb.control(item)))
});
onDrop() {
this.form.get('items').setValue(this.items);
}
Angular CDK предоставляет полный набор инструментов для реализации drag-and-drop с поддержкой всех необходимых сценариев - от простого переупорядочивания элементов до сложных взаимодействий между несколькими списками с кастомизацией поведения и визуальных эффектов.