完整代碼在最後,下面講解以此代碼爲例javascript
1.1 安裝@angular/material、@angular/cdkcss
cnpm install --save @angular/material @angular/cdkhtml
1.2 app.modules.ts導入java
import { DragDropModule } from '@angular/cdk/drag-drop';npm
imports: [bootstrap
...app
DragDropModuleide
]動畫
html編輯以下代碼便可:this
<div cdkDrag class="drag-box" drag me </div>
html:
<h3>列表排序</h3> <div class="box-list" cdkDropList (cdkDropListDropped)="drop($event)"> <div class="drag-box" *ngFor="let customer of customers" cdkDrag> {{customer.name}} </div> </div>
ts:
import { ...CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; customers = [ { name: 'Adam', age: 23 }, { name: 'Jack', age: 27 }, { name: 'Katherin', age: 26 }, { name: 'John', age: 30 }, { name: 'Watson', age: 42 }, ]; drop(event: CdkDragDrop<string[]>) { console.log('列表排序:', event, this.customers); moveItemInArray(this.customers, event.previousIndex, event.currentIndex); }
執行以下操做:
打印結果:
html:
<h3>橫向排序</h3> <div class="box-list-horizontal" cdkDropList cdkDropListOrientation="horizontal" (cdkDropListDropped)="drop($event)"> <div class="drag-box" *ngFor="let customer of customers" cdkDrag> {{customer.name}} </div> </div>
爲了設置動畫,咱們定義了一個以transform屬性爲目標的轉換。拖放CDK支持動畫:
--對列表中的元素進行拖動排序時的動畫=> .cdk-drag
.cdk-drag { transition: transform 100ms ease; }
--從動畫的位置到最終把它放在列表的位置上時的動畫=> .cdk-drag-animating
.cdk-drag-animating { transition: transform 300ms ease; }
使用.cdk-drag-placeholder來顯示佔位符元素,而不是實際的元素,由於它是在cdkDropList中拖動的。默認狀況下,這看起來與正在排序的元素徹底相同。
.cdk-drag-placeholder { background: #ccc; border: dotted 1px #999; transition: transform 500ms ease; }
拖拽時效果以下圖:
使用*cdkDragPlaceholder指令,咱們能夠用一個自定義的佔位符來代替默認的佔位符
html:
<div class="box-list customph" cdkDropList (cdkDropListDropped)="drop($event)"> <div class="drag-box dragList" *ngFor="let customer of customers" cdkDrag > <div class="box-custom-placeholder" *cdkDragPlaceholder></div> {{customer.name}} </div> </div>
css:
// 自定義佔位符 .customph{ .box-custom-placeholder { height: 28px; width: 100px; background: #fff; border: dotted 1px #0084ff; transition: transform 200ms ease; } &.box-list.cdk-drop-list-dragging .drag-box:not(.cdk-drag-placeholder) { transition: transform 500ms ease; } }
當提取並拖動cdkDrag元素時,能夠看到預覽元素。默認狀況下,預覽元素看起來與被拖動的元素徹底相同。
使用.cdk-drag-preview來定義預覽CSS:
// 預覽 .cdk-drag-preview { height: 28px; width: 100px; box-shadow: 0 3px 3px -3px #0084ff; }
咱們還須要使用*cdkDragPreview提供一個自定義模板:
<div cdkDropList class="box-list" (cdkDropListDropped)="drop($event)"> <div class="drag-box dragList" *ngFor="let customer of customers" cdkDrag> {{customer.name}} <p *cdkDragPreview>Age: {{customer.age}}</p> </div> </div>
咱們能夠使用cdkDropListConnectedTo屬性將一個或多個cdkDropList鏈接到一塊兒。而後設置cdkDropListData和cdkDragData,將數據與cdkDropList和cdkDrag關聯起來。
html:
<div class="box-list" cdkDropList #inactiveList="cdkDropList" id="Inactive Customers" [cdkDropListData]="inactiveCustomers" [cdkDropListConnectedTo]="[activeList]" (cdkDropListDropped)="drop1($event)"> <div class="drag-box dragList" [cdkDragData]="customer" *ngFor="let customer of inactiveCustomers" cdkDrag> {{customer.name}} </div> </div> <div class="box-list" cdkDropList #activeList="cdkDropList" id="Active Customers" [cdkDropListData]="activeCustomers" [cdkDropListConnectedTo]="[inactiveList]" (cdkDropListDropped)="drop1($event)"> <div class="drag-box dragList" [cdkDragData]="customer" *ngFor="let customer of activeCustomers" cdkDrag> {{customer.name}} </div> </div>
ts:
import { ...transferArrayItem } from '@angular/cdk/drag-drop'; inactiveCustomers = [ {name: 'Jack', age: 18}, {name: 'Katherin', age: 16}, {name: 'Adam', age: 36} ]; activeCustomers = [ {name: 'John', age: 10}, {name: 'Watson', age: 24} ]; drop1(event: CdkDragDrop<string[]>) { console.log('拖拽事件:event', event); if (event.previousContainer === event.container) { console.log('拖拽事件', `> 拖 '${event.item.data}' 到 '${event.container.id}'`); moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); } else { console.log('拖拽事件', `> 拖 '${event.item.data}' 到 '${event.container.id}'`); transferArrayItem( event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex); } }
執行以下操做:
打印結果:
CdkDropListGroup
CdkDropListGroup指令的範圍比CdkDropList要大一級。CdkDropListGroup能夠包含多個CdkDropList。並且當CdkDropListGroup包含多個CdkDropList的時候,這些CdkDropList直接是相互connect的(CdkDropList就不用去寫cdkDropListConnectedTo屬性了)。
<div cdkDropListGroup> <div class="box-list" cdkDropList id="Inactive Customers" [cdkDropListData]="inactiveCustomers" (cdkDropListDropped)="drop1($event)"> <div class="drag-box dragList" [cdkDragData]="customer" *ngFor="let customer of inactiveCustomers" cdkDrag> {{customer.name}} </div> </div> <div class="box-list" cdkDropList id="Active Customers" [cdkDropListData]="activeCustomers" (cdkDropListDropped)="drop1($event)"> <div class="drag-box dragList" [cdkDragData]="customer" *ngFor="let customer of activeCustomers" cdkDrag> {{customer.name}} </div> </div> </div>
Drag Event Handlers
– cdkDragStarted: 當用戶開始拖動時發出。
– cdkDragEnded: 當用戶中止拖動時發出。
– cdkDragEntered: 將item移動到新容器中時發出。
– cdkDragExited: 將item移出當前容器時發出。
Drop Event Handlers
– cdkDropListDropped: emits when an item was dropped inside the container.
– cdkDropListEntered: emits when a new item is dragged into this container.
– cdkDropListExited: emits when an item is dragged from this container into another container.
html:
<h3>事件監聽</h3> <div cdkDrag class="drag-box" (cdkDragStarted)="dragStarted($event)" (cdkDragEnded)="dragEnded($event)" (cdkDragMoved)="dragMoved($event)" > drag me </div> <p>{{state}} {{position}}</p>
ts:
import { CdkDragEnd, CdkDragStart, CdkDragMove... } from '@angular/cdk/drag-drop'; dragStarted(event: CdkDragStart) { this.state = '拖拽開始'; console.log('拖拽開始'); } dragEnded(event: CdkDragEnd) { this.state = '拖拽結束'; console.log('拖拽結束'); } dragMoved(event: CdkDragMove) { console.log('dragMoved'); this.position = `> Position X: ${event.pointerPosition.x} - Y: ${event.pointerPosition.y}`; }
html:
<div class="box-list" cdkDropList #inactiveList="cdkDropList" id="Inactive Customers" [cdkDropListData]="inactiveCustomers" [cdkDropListConnectedTo]="[activeList]" (cdkDropListDropped)="drop1($event)" (cdkDropListEntered)="dropListEntered($event)" (cdkDropListExited)="dropListExited($event)"> <div class="drag-box dragList" [cdkDragData]="customer" (cdkDragEntered)="dragEntered($event)" (cdkDragExited)="dragExited($event)" *ngFor="let customer of inactiveCustomers" cdkDrag> {{customer}} </div> </div> <div class="box-list" cdkDropList #activeList="cdkDropList" id="Active Customers" [cdkDropListData]="activeCustomers" [cdkDropListConnectedTo]="[inactiveList]" (cdkDropListDropped)="drop1($event)"> <div class="drag-box dragList" [cdkDragData]="customer" *ngFor="let customer of activeCustomers" cdkDrag> {{customer}} </div> </div>
ts:
import { ...CdkDragEnter, CdkDragExit} from '@angular/cdk/drag-drop'; dragEntered(event: CdkDragEnter) { console.log(`drag:把 '${event.item.data}' 拖進 '${event.container.id}' `); } dragExited(event: CdkDragExit) { console.log(`drag:把 '${event.item.data}' 從 '${event.container.id}' 中拖出 `); } dropListEntered(event: CdkDragEnter) { console.log(`drop:'${event.container.id}' 中拖進了 '${event.item.data}'`); } dropListExited(event: CdkDragExit) { console.log(`drop:從 '${event.container.id}' 中拖出 '${event.item.data}'`); }
執行以下操做
打印結果:
再執行以下操做:
打印結果:
拖拽過程當中交換item的時候回調
<div class="box-list" cdkDropList #activeList="cdkDropList" id="Active Customers" [cdkDropListData]="activeCustomers" [cdkDropListConnectedTo]="[inactiveList]" (cdkDropListDropped)="drop1($event)" (cdkDropListSorted)="dropListSorted($event)"> <div class="drag-box dragList" [cdkDragData]="customer" *ngFor="let customer of activeCustomers" cdkDrag> {{customer.name}} </div> </div>
ts:
dropListSorted(event: CdkDropList) { console.log('Sorted:', event); }
enterPredicate: (drag: CdkDrag, drop: CdkDropList) => boolean
指定哪些item是能夠拖拽到當前容器
html:
<div class="box-list" cdkDropList #activeList="cdkDropList" id="Active Customers" [cdkDropListData]="activeCustomers" [cdkDropListConnectedTo]="[inactiveList]" (cdkDropListDropped)="drop1($event)" [cdkDropListEnterPredicate]="predicate"> <div class="drag-box dragList" [cdkDragData]="customer" *ngFor="let customer of activeCustomers" cdkDrag> {{customer.name}} </div> </div>
ts:
import { ...CdkDrag, CdkDropList } from '@angular/cdk/drag-drop'; predicate(drag: CdkDrag, drop: CdkDropList) { console.log('predicate:', drag, drop); return drag.data.age >= 18; }
CdkDrag屬性:
CdkDropList屬性
代碼:
html:
<div class="drag-box" cdkDrag> drag me </div> <h3>鎖定方向</h3> <div class="drag-box" cdkDragLockAxis="y" cdkDrag> only up/down </div> <div class="drag-box" cdkDragLockAxis="x" cdkDrag> only left/right </div> <h3>事件監聽</h3> <div cdkDrag class="drag-box" (cdkDragStarted)="dragStarted($event)" (cdkDragEnded)="dragEnded($event)" (cdkDragMoved)="dragMoved($event)" > drag me </div> <p>{{state}} {{position}}</p> <h3>拖拽handler</h3> <div class="drag-box-with-handler drag-box" cdkDrag> <div class="box-handler" cdkDragHandle> 點我拖拽 </div> </div> <h3>列表排序</h3> <div class="box-list" cdkDropList (cdkDropListDropped)="drop($event)"> <div class="drag-box dragList" *ngFor="let customer of customers" cdkDrag> {{customer.name}} </div> </div> <h3>橫向排序</h3> <div class="box-list-horizontal" cdkDropList cdkDropListOrientation="horizontal" (cdkDropListDropped)="drop($event)"> <div class="drag-box dragListH" *ngFor="let customer of customers" cdkDrag> {{customer.name}} </div> </div> <h3>placeholder 默認佔位符元素</h3> <div>使用.cdk-drag-placeholder來顯示佔位符元素,而不是實際的元素, 由於它是在cdkDropList中拖動的。默認狀況下,佔位符元素看起來與正在排序的元素徹底相同。</div> <div class="box-list defplaceh" cdkDropList (cdkDropListDropped)="drop($event)"> <div class="drag-box dragList" *ngFor="let customer of customers" cdkDrag> {{customer.name}} </div> </div> <h3>placeholder 自定義佔位符元素</h3> <div>使用*cdkDragPlaceholder指令,咱們能夠用一個自定義的佔位符來代替默認的佔位符</div> <div class="box-list customph" cdkDropList (cdkDropListDropped)="drop($event)"> <div class="drag-box dragList" *ngFor="let customer of customers" cdkDrag > <div class="box-custom-placeholder" *cdkDragPlaceholder></div> {{customer.name}} </div> </div> <h3>預覽 Preview</h3> <div>當提取並拖動cdkDrag元素時,能夠看到預覽元素。默認狀況下, 預覽元素看起來與被拖動的元素徹底相同。</div> <div cdkDropList class="box-list" (cdkDropListDropped)="drop($event)"> <div class="drag-box dragList" *ngFor="let customer of customers" cdkDrag> {{customer.name}} <p *cdkDragPreview>Age: {{customer.age}}</p> </div> </div> <h3>兩個列表間拖放</h3> <div class="twoList"> <div class="box-list" cdkDropList #inactiveList="cdkDropList" id = "Inactive Customers" [cdkDropListData]="inactiveCustomers" [cdkDropListConnectedTo]="[activeList]" (cdkDropListDropped)="drop1($event)" (cdkDropListEntered)="dropListEntered($event)" (cdkDropListExited)="dropListExited($event)" [cdkDropListEnterPredicate]="predicate" > <div class="drag-box dragList" [cdkDragData]="customer" (cdkDragEntered)="dragEntered($event)" (cdkDragExited)="dragExited($event)" *ngFor="let customer of inactiveCustomers;isLast as last" cdkDrag> {{customer.name}} </div> </div> <div class="box-list" cdkDropList #activeList="cdkDropList" id = "Active Customers" [cdkDropListData]="activeCustomers" [cdkDropListConnectedTo]="[inactiveList]" (cdkDropListDropped)="drop1($event)" [cdkDropListEnterPredicate]="predicate" (cdkDropListSorted)="dropListSorted($event)" > <div class="drag-box dragList" [cdkDragData]="customer" *ngFor="let customer of activeCustomers" cdkDrag> {{customer.name}} </div> </div> </div> <!-- <h3>兩個列表間拖放 cdkDropListGroup</h3> <div class="twoList" cdkDropListGroup> <div class="box-list" cdkDropList id = "Inactive Customers" [cdkDropListData]="inactiveCustomers" (cdkDropListDropped)="drop1($event)"> <div class="drag-box dragList" [cdkDragData]="customer" *ngFor="let customer of inactiveCustomers" cdkDrag> {{customer.name}} </div> </div> <div class="box-list" cdkDropList id = "Active Customers" [cdkDropListData]="activeCustomers" (cdkDropListDropped)="drop1($event)"> <div class="drag-box dragList" [cdkDragData]="customer" *ngFor="let customer of activeCustomers" cdkDrag> {{customer.name}} </div> </div> </div> -->
ts:
import { Component, OnInit } from '@angular/core'; import { CdkDragEnd, CdkDragStart, CdkDragMove, CdkDragDrop, CdkDragEnter, CdkDragExit, moveItemInArray, transferArrayItem, CdkDrag, CdkDropList } from '@angular/cdk/drag-drop'; @Component({ selector: 'app-drag-drop', templateUrl: './drag-drop.component.html', styleUrls: ['./drag-drop.component.scss'] }) export class DragDropComponent implements OnInit { state = ''; position = ''; customers = [ { name: 'Adam', age: 23 }, { name: 'Jack', age: 27 }, { name: 'Katherin', age: 26 }, { name: 'John', age: 30 }, { name: 'Watson', age: 42 }, ]; inactiveCustomers = [ {name: 'Jack', age: 18}, {name: 'Katherin', age: 16}, {name: 'Adam', age: 36} ]; activeCustomers = [ {name: 'John', age: 10}, {name: 'Watson', age: 24} ]; constructor() { } ngOnInit() { } dragStarted(event: CdkDragStart) { this.state = '拖拽開始'; console.log('拖拽開始'); } dragEnded(event: CdkDragEnd) { this.state = '拖拽結束'; console.log('拖拽結束'); } dragMoved(event: CdkDragMove) { console.log('dragMoved'); this.position = `> Position X: ${event.pointerPosition.x} - Y: ${event.pointerPosition.y}`; } dragEntered(event: CdkDragEnter) { console.log(`drag:把 '${event.item.data}' 拖進 '${event.container.id}' `); } dragExited(event: CdkDragExit) { console.log(`drag:把 '${event.item.data}' 從 '${event.container.id}' 中拖出 `); } dropListEntered(event: CdkDragEnter) { console.log(`drop:'${event.container.id}' 中拖進了 '${event.item.data}'`); } dropListExited(event: CdkDragExit) { console.log(`drop:從 '${event.container.id}' 中拖出 '${event.item.data}'`); } drop(event: CdkDragDrop<string[]>) { console.log('列表排序:', event, this.customers); moveItemInArray(this.customers, event.previousIndex, event.currentIndex); } drop1(event: CdkDragDrop<string[]>) { console.log('拖拽事件:event', event); if (event.previousContainer === event.container) { console.log('拖拽事件', `> 拖 '${event.item.data}' 到 '${event.container.id}'`); moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); } else { console.log('拖拽事件', `> 拖 '${event.item.data}' 到 '${event.container.id}'`); transferArrayItem( event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex); } } predicate(drag: CdkDrag, drop: CdkDropList) { console.log('predicate:', drag, drop); return drag.data.age >= 18; } dropListSorted(event: CdkDropList) { console.log('Sorted:', event); } }
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { ScrollingModule } from '@angular/cdk/scrolling'; import { MatCardModule } from '@angular/material'; import { DragDropModule } from '@angular/cdk/drag-drop'; // import { VIEWPORT_RULER_PROVIDER } from '@angular/cdk/scrolling'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { VirtualScrollComponent } from './virtual-scroll/virtual-scroll.component'; import { DragDropComponent } from './drag-drop/drag-drop.component'; @NgModule({ declarations: [ AppComponent, VirtualScrollComponent, DragDropComponent ], imports: [ BrowserModule, AppRoutingModule, ScrollingModule, MatCardModule, DragDropModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
css:
.drag-box{ height: 100px; width: 100px; border: 1px solid #000; } .box-handler{ width: 100%; height: 20px; background: #ccc; } .dragList{ height: 28px; margin: 5px 0; } .dragListH{ display: inline-block; margin: 0 5px; height: 28px; width: 55px; } // 動畫效果 // .cdk-drag { // transition: transform 100ms ease; // } .cdk-drag-animating { transition: transform 300ms ease; } // 佔位符 默認 placeholder .defplaceh .cdk-drag-placeholder { background: #ccc; border: dotted 1px #999; transition: transform 500ms ease; } // 自定義佔位符 .customph{ .box-custom-placeholder { height: 28px; width: 100px; background: #fff; border: dotted 1px #0084ff; transition: transform 200ms ease; } &.box-list.cdk-drop-list-dragging .drag-box:not(.cdk-drag-placeholder) { transition: transform 500ms ease; } } // 預覽 .cdk-drag-preview { height: 28px; width: 100px; box-shadow: 0 3px 3px -3px #0084ff; } .twoList{ overflow: hidden; >div{ float: left; margin: 10px; } }