背景
有这样一个需求:
使用的是原生 CDK 拖拽组件,找了很久也没有找到拖拽复制的,基础示例是从一个容器拖拽进另一个元素之后,该元素会从原容器中删除,如下图
找了很久的资料,最终发现了官方有这样一个 issue: https://github.com/angular/components/issues/13100 ,里面就充分阐述了这个问题,可惜的是官方并没有给出解决方案,通过关联的 pull request 看到官方提供了一个工具函数:copyArrayItem,它只是在原有的交互上又给原容器加了一遍拖拽的元素,当元素从一个容器到另一个容器(不要松鼠标),它还是会删除原容器的元素,会给用户造成一些错觉,如图:
解决方案
这也是一个骚操作,思路是:拖拽的过程中用一个跟原容器一模一样的容器替代它,等拖拽结束后在恢复原视图,用一个状态来控制两个容器的隐藏/显示,这样的话在从一个容器移入新容器的整个过程中原容器会隐藏掉,也就是说这个容器的元素在被删除的一瞬间,用户的视觉下是看不到的,用户只能看到跟原容器一模一样的容器,而这个容器是静态的,元素从开始到最后都不会减少。
代码
效果图如文章第一节所示
拓展
为什么不是只复制出这个元素而是复制整个容器呢?
因为删除这个动作是 dropList 控制的,数据也是容器控制的,进入新容器的一瞬间依旧会删除(cdk 内部控制的,不支持外部重写)。
把 style.display 换成 ngIf 是否可行?
不行,因为使用 ngIf 整个 dom 就都不会渲染了,那么拖拽组件就找不到宿主导致无法拖拽,使用 display,外层 dom 存在只是样式隐藏了,但是真实 dom 依旧存在。