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

如何在Angular中实现支持自由拖拽放置的自定义看板?

Angular拖拽自由看板实现方案

Angular自带的DragDropModule完全支持你要的「右侧列表拖拽复制到左侧看板、看板内元素自由移动」的需求,你当前代码无法触发事件的核心原因是事件绑定语法错误、以及拖拽区域没有做关联配置,按以下步骤修改即可:

问题排查

你写的cdkDragEnded="dragEndedProcess()"缺少Angular事件绑定必需的括号,正确写法是(cdkDragEnded)="dragEndedProcess()",缺少括号的情况下框架不会把它识别为事件绑定,自然不会触发对应方法。
另外你没有关联左右两个拖拽区域,也没有对左侧看板做自由拖拽的适配,才会出现逻辑不生效的问题。

具体实现步骤

  1. 基础配置修正
  • 右侧元素列表容器加cdkDropList标识,配置[cdkDropListConnectedTo]关联左侧看板,开启cdkDropListCopyMode实现复制而非移动源元素
  • 左侧看板容器同样加cdkDropList标识,绑定(cdkDropListDropped)事件处理元素拖拽落下的逻辑
  1. 复制逻辑实现
  • 拖拽结束时从事件对象中拿到携带的元素数据,直接新增到左侧看板的元素渲染数组中,不要操作右侧源数组即可实现复制效果
  • 每个看板元素额外存储left、top坐标属性,用于记录元素在看板内的位置
  1. 看板内自由移动适配
  • 左侧看板设置position: relative,内部的拖拽元素设置position: absolute,保证坐标相对于看板计算
  • 看板内的元素绑定(cdkDragEnded)事件,拖拽结束后更新元素自身的坐标属性,位置即可持久化

代码示例

模板代码

<!-- 右侧元素列表 -->
<div 
  cdkDropList 
  #sourceList="cdkDropList"
  [cdkDropListData]="rightItemList"
  [cdkDropListConnectedTo]="['leftBoard']"
  cdkDropListCopyMode
  class="right-list"
>
  <div 
    class="rfid-box"
    cdkDrag
    *ngFor="let item of rightItemList"
    [cdkDragData]="item"
  >
    {{item.name}}
  </div>
</div>

<!-- 左侧看板 -->
<div 
  cdkDropList 
  id="leftBoard"
  class="left-box"
  [cdkDropListData]="boardItemList"
  (cdkDropListDropped)="onItemDropped($event)"
>
  <!-- 动态渲染拖拽生成的元素 -->
  <div 
    class="board-item"
    cdkDrag
    cdkDragBoundary=".left-box"
    *ngFor="let item of boardItemList"
    [style.left.px]="item.left"
    [style.top.px]="item.top"
    (cdkDragEnded)="onBoardItemDragEnd($event, item)"
  >
    {{item.name}}
  </div>
</div>

组件逻辑代码

import { CdkDragDrop, moveItemInArray, CdkDragEnd } from '@angular/cdk/drag-drop';

// 组件类内部
rightItemList = [
  {id: 1, name: 'Télécommande'},
  // 其他右侧列表元素
];
boardItemList = [];

// 元素从右侧拖拽到左侧看板触发
onItemDropped(event: CdkDragDrop<any[]>) {
  // 只处理从右侧列表拖过来的元素
  if (event.previousContainer !== event.container) {
    // 复制元素到看板,初始化坐标为落下的位置
    const newItem = {...event.previousContainer.data[event.previousIndex]};
    newItem.left = event.dropPoint.x - event.container.element.nativeElement.offsetLeft;
    newItem.top = event.dropPoint.y - event.container.element.nativeElement.offsetTop;
    this.boardItemList.push(newItem);
  }
}

// 看板内元素拖拽结束更新坐标
onBoardItemDragEnd(event: CdkDragEnd, item: any) {
  const position = event.source.getFreeDragPosition();
  item.left = position.x;
  item.top = position.y;
}

样式代码

.left-box {
  position: relative;
  width: 70%;
  height: 100vh;
  border: 1px solid #eee;
}
.right-list {
  width: 30%;
  padding: 16px;
  border-left: 1px solid #eee;
}
.board-item {
  position: absolute;
  padding: 8px 12px;
  background: #fff;
  border: 1px solid #ccc;
  cursor: move;
}
.rfid-box {
  padding: 8px 12px;
  margin-bottom: 8px;
  background: #f5f5f5;
  cursor: move;
}

效果示例

drag-and-drop-board

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 06:15:00