前言

写到表单性能的时候,就思考如果表单可能拖动式地增加,无疑可能增强用户的应用体验感。所以就尝试着实现拖动性能。如下图,可能将一个表单拖动到另一个表单。

环境配置

应用到了angular的cdk:@angular/cdk/drag-drop

Angualr drag-drop外面的性能能让咱们十分不便的解决页面上视图的拖拽(自在拖拽、列表排序拖拽、列表之间拖拽)问题。

官网:https://material.angular.io/c...

cdk是Angular Material 下的一个模块.咱们装置一下Material。

装置material

ng add @angular/material

ng add命令将装置 Angular Material、 组件开发工具包 (CDK)

Module导入

import { DragDropModule } from '@angular/cdk/drag-drop';imports: [...DragDropModule]

性能实现

讲一下最罕用的几种用法

拖拽

html代码:
最次要的就是加上了 cdkDrag

<div cdkDrag> drag me</div>

成果:

排序

应用cdkDropList,它增加在一组元素增加cdkDrag可拖动元素的汇合里面。随着元素的挪动,我的项目将主动重新排列。

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);  }

效果图:





当然还能够横向排序,只须要增加cdkDropListOrientation="horizontal"

<div class="box-list-horizontal" cdkDropList cdkDropListOrientation="horizontal">

增加动画

看起来下面的效果图有些不太好看,咱们能够给它增加一点动画。

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);}



效果图:


还有其余的其余的一些性能将不再一一讲述,比方拖放地位锁定、设置拖放边界、拖放禁用性能。
能够看看官网:https://material.angular.io/c...

两个列表之间的拖拽

目前须要应用的是列表之间的拖拽,所以重点讲一下这个。

列表之间的连贯

应用cdkDropListConnectedTo和id,能够连贯两个表,使它们之间可能拖动本人的元素到另一个表中。

<div cdkDropList id="list-one" [cdkDropListConnectedTo]="['list-two']"></div><div cdkDropList id="list-two" [cdkDropListConnectedTo]="['list-one']"></div>



也能够应用cdkDropListGroup。cdkDropListGroup在下的所有表都将主动连贯到所有其余列表。我采纳的是这种。

<div cdkDropListGroup>  <!-- All lists in here will be connected. -->  <div cdkDropList *ngFor="let list of lists"></div></div>

依据需要写代码

首先,定义了一个表,需要是:不能排序,另一个不能拖动元素到此表单

  <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>


定义了另一个表,需要是:能够排序,另一个表的元素拖动过去的时候,原来的元素不会隐没。

<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>

效果图:



ts:
当元素从右边的表拖动到左边的表的时候,或者左边的表排序的时候,左边的表会执行dropNowList()函数。函数中进行了判断,如代码中正文所示

/**   * 现有表单   * @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)    }  }

遇到的问题

动静渲染

其实最开始想的是,元素一拖过来就动静渲染。然而,动静组件是一个整体,咱们并不能拖动其中的某一个组件,只能拖动整体。如下效果图:



所以最初放弃了动静渲染,让用户拖动好了表单再点击预览按钮。

拖动成果

从一个表拖动元素到另一个表到时候,这个元素在源表中会隐没,尽管拖动过来之后会回来,然而看起来逻辑并不好。

示例:

所以须要实现的是,拖动元素的时候,这个元素在源表单不动。

但仿佛DragModule并没有属性或者函数能够让咱们调用来解决这个问题。

在github有一场对这个问题的大型探讨:
https://github.com/angular/co...

但仿佛实现起来有点麻烦。

这个问题目前还不影响性能的实现,待前期有工夫的时候再解决。