基于 Angular CDK 实现拖拽复制元素

背景

有这样一个需求:

使用的是原生 CDK 拖拽组件,找了很久也没有找到拖拽复制的,基础示例是从一个容器拖拽进另一个元素之后,该元素会从原容器中删除,如下图

找了很久的资料,最终发现了官方有这样一个 issue:  https://github.com/angular/components/issues/13100 ,里面就充分阐述了这个问题,可惜的是官方并没有给出解决方案,通过关联的 pull request 看到官方提供了一个工具函数:copyArrayItem,它只是在原有的交互上又给原容器加了一遍拖拽的元素,当元素从一个容器到另一个容器(不要松鼠标),它还是会删除原容器的元素,会给用户造成一些错觉,如图:


解决方案

这也是一个骚操作,思路是:拖拽的过程中用一个跟原容器一模一样的容器替代它,等拖拽结束后在恢复原视图,用一个状态来控制两个容器的隐藏/显示,这样的话在从一个容器移入新容器的整个过程中原容器会隐藏掉,也就是说这个容器的元素在被删除的一瞬间,用户的视觉下是看不到的,用户只能看到跟原容器一模一样的容器,而这个容器是静态的,元素从开始到最后都不会减少。

代码


效果图如文章第一节所示

拓展

为什么不是只复制出这个元素而是复制整个容器呢?

因为删除这个动作是 dropList 控制的,数据也是容器控制的,进入新容器的一瞬间依旧会删除(cdk 内部控制的,不支持外部重写)。

把 style.display 换成 ngIf 是否可行?

不行,因为使用 ngIf 整个 dom 就都不会渲染了,那么拖拽组件就找不到宿主导致无法拖拽,使用 display,外层 dom 存在只是样式隐藏了,但是真实 dom 依旧存在。

源码及示例

https://stackblitz.com/edit/cdk-drag-drop-copy?file=src/app/cdk-drag-drop-connected-sorting-example.html