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
相关产品推荐
相关产品推荐

