foreword
When writing the form function, consider that if the form can be added by dragging, it will undoubtedly enhance the user's experience. So try to implement the drag function. As shown below, you can drag one form to another form.
Environment configuration
Using angular's cdk: @angular/cdk/drag-drop
The functions in Angualr drag-drop allow us to easily handle the dragging of views on the page (free dragging, list sorting dragging, dragging between lists).
Official website: https://material.angular.io/cdk/drag-drop/overview
cdk is a module under Angular Material. Let's install Material.
install material
ng add @angular/material
The ng add command will install Angular Material, the Component Development Kit (CDK)
Module import
import { DragDropModule } from '@angular/cdk/drag-drop';
imports: [
...
DragDropModule
]
Function realization
Talk about the most common usage
drag
html code:
The most important thing is to add cdkDrag
<div cdkDrag> drag me</div>
Effect:
sort
Use cdkDropList, which adds a set of elements outside the collection of cdkDrag draggable elements. Items will automatically rearrange as elements are moved.
html:
<div class="list-group" cdkDropList
(cdkDropListDropped)="drop($event)">
<div class="list-group-item row" *ngFor="let customer of customers" cdkDrag>
{{customer.name}}
</div>
</div>
ts:
drop(event: CdkDragDrop<string[]>) {
moveItemInArray(this.customers, event.previousIndex, event.currentIndex);
}
Effect picture:
Of course, you can also sort horizontally, just add cdkDropListOrientation="horizontal"
<div class="box-list-horizontal" cdkDropList
cdkDropListOrientation="horizontal">
Add animation
It looks like the rendering above doesn't look good, we can add a little animation to it.
css:
// 拖拽时显示的占位符元素,而不是实际的元素
.cdk-drag-placeholder {
opacity: 0;
}
// 从动画的位置到最终把它放在列表的位置上时的动画
.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
// 拖动元素时,看到的预览元素
.cdk-drag-preview {
box-sizing: border-box;
border-radius: 4px;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
// 拖动元素时,其他元素改变位置看到的动画
.list-group.cdk-drop-list-dragging .list-group-item:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
Effect picture:
There are other other functions that will not be described one by one, such as drag and drop position locking, setting drag and drop boundaries, and drag and drop disable functions.
You can take a look at the official website: https://material.angular.io/cdk/drag-drop/examples
Drag and drop between two lists
At present, we need to use drag and drop between lists, so let's focus on this.
connection between lists
Using cdkDropListConnectedTo and id, you can connect two tables so that they can drag their own elements into the other table.
<div cdkDropList id="list-one" [cdkDropListConnectedTo]="['list-two']"></div>
<div cdkDropList id="list-two" [cdkDropListConnectedTo]="['list-one']"></div>
You can also use cdkDropListGroup. All tables under cdkDropListGroup will be automatically joined to all other lists. I use this.
<div cdkDropListGroup>
<!-- All lists in here will be connected. -->
<div cdkDropList *ngFor="let list of lists"></div>
</div>
Write code on demand
First, a table is defined, the requirements are: can not sort, another can not drag elements to this form
<div class="row">
<div class="col-2">
<h2>可用表单</h2>
<div
cdkDropList
[cdkDropListData]="availableItems" // 拖动时所带的元素
cdkDropListSortingDisabled // 禁用排序
[cdkDropListEnterPredicate]= "noReturnPredicate" // 定义了一个函数,返回false, 表示别的表单不能拖动元素到此表单
class="list-group">
<div class="list-group-item" *ngFor="let item of availableItems" cdkDrag>
<label> {{item.content}}</label>
</div>
</div>
</div>
</div>
Another table is defined, and the requirement is: it can be sorted, and when the elements of another table are dragged over, the original elements will not disappear.
<div class="col-6">
<h2>目前表单</h2>
<div
cdkDropList
class="list-group"
[cdkDropListData]="nowItem"
(cdkDropListDropped)="dropNowList($event)">
<div class="list-group-item row" cdkDrag *ngFor="let item of nowItem">
{{item.content}}
</div>
</div>
</div>
Effect picture:
ts:
When an element is dragged from the left table to the right table, or the right table is sorted, the right table will execute the dropNowList() function. The judgment is made in the function, as shown in the comments in the code
/**
* 现有表单
* @param event
*/
dropNowList(event: CdkDragDrop<FormItem[], any>) {
// 如果前容器等于现容器,说明是在排序,交换元素的位置
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
// 如果不同,说明是从另一个表过来的元素,获取元素前容器的数据,复制元素,插入到本表中
// 如果使用transferItem(),则源元素会消失
copyArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex)
}
}
problems encountered
Dynamic rendering
In fact, the first thought was to dynamically render the element as soon as it was dragged over. However, a dynamic component is a whole, and we can't drag one of the components, only the whole. The following effect diagram:
So finally gave up dynamic rendering, let the user drag the form and then click the preview button.
drag effect
When dragging an element from one table to another table, the element will disappear in the source table, although it will come back after dragging, but it seems that the logic is not good.
Example:
So what needs to be realized is that when the element is dragged, the element does not move in the source form.
But it seems that DragModule has no property or function that we can call to solve this problem.
There is a large discussion on this issue on github:
https://github.com/angular/components/issues/13100
But it seems a bit cumbersome to implement.
This problem does not affect the implementation of the function at present, and will be solved later when there is time.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。