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

Angular中实现选中多行的拖拽移动功能(无需ag-grid)

Angular 多行拖拽移动实现方案(无ag-grid)

1. 改造拖拽起始逻辑(更新onRowDragStart)

原代码仅传递单个行索引,现在需要把所有选中行的索引集合存入dataTransfer,确保拖拽过程中能获取到全部待移动的目标行:

onRowDragStart(event: DragEvent) {
  if (this.grid.areRowsDraggable) {
    // 假设你用selectedRowIndexes数组存储已选中的行索引
    const selectedIndexes = this.selectedRowIndexes.join(',');
    event.dataTransfer!.setData('text/plain', selectedIndexes);
    // 添加拖拽时的半透明视觉反馈
    (event.target as HTMLElement).style.opacity = '0.5';
    // 缓存拖拽起始时的选中行数据,避免拖拽过程中选中状态变化影响结果
    this.draggingRows = [...this.selectedRowIndexes].map(idx => this.dataList[idx]);
  }
}

2. 处理拖拽经过事件(onRowDragOver)

在拖拽经过行时添加高亮提示,同时记录目标插入位置:

onRowDragOver(event: DragEvent, rowIndex: number) {
  event.preventDefault(); // 必须阻止默认行为,才能触发后续drop事件
  // 移除之前的高亮行样式
  document.querySelectorAll('.drag-over-highlight').forEach(el => el.classList.remove('drag-over-highlight'));
  // 给当前经过的行添加上边框高亮
  const targetRow = event.target as HTMLElement;
  targetRow.classList.add('drag-over-highlight');
  // 记录当前目标插入位置
  this.targetDropIndex = rowIndex;
}

3. 核心:处理放置事件(onRowDrop)

根据选中行和目标位置,重新调整数据数组的顺序:

onRowDrop(event: DragEvent) {
  event.preventDefault();
  // 清理视觉样式
  (event.target as HTMLElement).style.opacity = '1';
  document.querySelectorAll('.drag-over-highlight').forEach(el => el.classList.remove('drag-over-highlight'));

  // 解析拖拽携带的选中行索引集合
  const selectedIndexesStr = event.dataTransfer!.getData('text/plain');
  const selectedIndexes = selectedIndexesStr.split(',').map(Number);
  
  if (!selectedIndexes.length || this.targetDropIndex === undefined) return;

  // 1. 从原数据中移除选中的行
  const draggedRows = selectedIndexes.map(idx => this.dataList[idx]);
  const filteredData = this.dataList.filter((_, idx) => !selectedIndexes.includes(idx));

  // 2. 修正插入位置:若目标位置在选中行的原范围内,需调整插入点避免偏移
  let insertIndex = this.targetDropIndex;
  const minSelectedIdx = Math.min(...selectedIndexes);
  if (insertIndex > minSelectedIdx) {
    insertIndex -= selectedIndexes.length;
  }

  // 3. 将拖拽行插入目标位置,更新数据源
  this.dataList = [
    ...filteredData.slice(0, insertIndex),
    ...draggedRows,
    ...filteredData.slice(insertIndex)
  ];

  // 4. 更新选中行索引,保持拖拽后的选中状态
  this.selectedRowIndexes = Array.from({length: draggedRows.length}, (_, i) => insertIndex + i);
  this.targetDropIndex = undefined;
  this.draggingRows = [];
}

4. 模板层绑定与样式配合

在表格行上绑定拖拽事件,添加选中状态和拖拽相关样式:

<table>
  <tr 
    *ngFor="let item of dataList; let i = index"
    draggable="true"
    [class.selected]="selectedRowIndexes.includes(i)"
    (dragstart)="onRowDragStart($event)"
    (dragover)="onRowDragOver($event, i)"
    (drop)="onRowDrop($event)"
    (dragend)="onRowDragEnd($event)"
  >
    <td>{{item.name}}</td>
    <!-- 其他列内容 -->
  </tr>
</table>

对应的CSS样式:

tr.selected {
  background-color: #e0e0e0;
}
tr.drag-over-highlight {
  border-top: 2px solid #2196F3;
}
tr[draggable="true"] {
  cursor: grab;
}
tr[draggable="true"]:active {
  cursor: grabbing;
}

5. 拖拽结束事件(onRowDragEnd)

用于清理临时样式和状态:

onRowDragEnd(event: DragEvent) {
  (event.target as HTMLElement).style.opacity = '1';
  document.querySelectorAll('.drag-over-highlight').forEach(el => el.classList.remove('drag-over-highlight'));
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 11:37:35