You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Angular CDK Drag-Drop更新拖拽项属性时重复条目同步更新问题

问题描述

我有一个条目列表,需要将每个条目拖拽至可放置容器中,当前使用@angular/cdk/drag-drop的copyArrayItem方法实现复制拖拽,希望拖拽后能更新条目部分属性。但遇到问题:把‘Item-1’两次拖拽到容器后,更新其中一个条目的属性时,两个条目属性会同步变化。请问如何解决,或者怎么对拖拽到容器里的唯一条目单独更新属性?

问题根源

copyArrayItem默认执行浅拷贝,两次拖拽同一个源条目时,容器内的两个条目指向同一个内存引用。因此修改其中一个条目属性时,另一个会同步变化。

解决方案

放弃直接使用copyArrayItem,手动创建源条目的深拷贝后再添加到目标数组,确保每个拖拽生成的条目都是独立对象。

修改后的关键代码

1. 更新dropControl方法(替换浅拷贝为深拷贝)

dropControl(event: any): void {
  if (event.previousContainer !== event.container) {
    // 对源条目执行深拷贝,避免引用共享
    const copiedControl = JSON.parse(JSON.stringify(event.previousContainer.data[event.previousIndex]));
    // 将深拷贝后的条目插入目标数组
    event.container.data.splice(event.currentIndex, 0, copiedControl);
    this.openDetailsEditorDialog(event);
  } else {
    moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
  }
  if (event.previousContainer.data) {
    this.controls = this.controls.filter((control) => !control.droppedFlag);
  }
}

2. 处理特殊类型的深拷贝(可选)

如果ControlType包含函数、Symbol、循环引用等JSON无法序列化的类型,改用structuredClone API实现深拷贝:

const copiedControl = structuredClone(event.previousContainer.data[event.previousIndex]);

3. 同步更新dropListExited方法(避免潜在的引用问题)

dropListExited(event: any): void {
  const currentIndex = event.container.data.findIndex(
    (control: ControlType) => control.type === event.item.data.type
  );
  // 对条目执行深拷贝后再添加回源列表
  const clonedItem = JSON.parse(JSON.stringify(event.item.data));
  this.controls.splice(currentIndex + 1, 0, {
    ...clonedItem,
    droppedFlag: true,
  });
}

原理说明

深拷贝会完整复制对象的所有层级属性,生成一个全新的内存对象。这样容器内的每个条目都拥有独立的引用,修改其中一个时不会影响其他条目。

内容的提问来源于stack exchange,提问作者Akhil Joseph

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 17:40:47