8

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.
image.png

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:
dragme.gif

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:
list1.gif





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:

list.gif


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:

form.gif



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:

form2.gif



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:

form1.gif

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.


weiweiyi
1k 声望123 粉丝