Angular结合SortableJS拖拽放置后如何获取目标数组及元素信息
实现方案
SortableJS 本身和业务数据结构解耦,不会直接返回目标数组引用,只需要在初始化拖拽实例时给列表容器DOM绑定自定义关联数据,就能在onEnd事件里拿到所有需要的信息,完全满足Angular场景下直接操作数据对象、获取目标分组标识的需求。
核心逻辑说明
onEnd事件对象自带5个核心DOM属性,是所有信息的来源:
evt.item:被拖拽的DOM节点evt.from:拖拽起始位置所属的列表容器DOMevt.to:拖拽结束位置所属的列表容器DOMevt.oldIndex:元素在原列表的索引位置evt.newIndex:元素在新列表的索引位置
你只需要在初始化每个可拖拽列表时,把对应的数组标识、数组引用绑定到容器DOM上,拖拽结束时直接从evt.from和evt.to上读取绑定的数据即可。
具体实现步骤
1. 初始化时给列表容器绑定业务关联数据
以你给出的数据源结构为例,先给两个数组对应的列表DOM绑定自定义属性:
// 你的业务数据源 const pageData = { "array_1": [ {item:"#1"},{item:"#2"},{item:"#3"}, ], "array_2": [ {item:"#4"},{item:"#5"},{item:"#6"}, ], } // 拿到两个列表的容器DOM const list1Container = document.querySelector('.list-array-1') const list2Container = document.querySelector('.list-array-2') // 绑定数组标识、数组引用到DOM上 list1Container.dataset.listName = 'array_1' list1Container.listRef = pageData.array_1 list2Container.dataset.listName = 'array_2' list2Container.listRef = pageData.array_2
2. 初始化Sortable实例,在onEnd回调中读取数据
两个列表设置相同的group属性支持跨列表拖拽,在公共的onEnd回调中直接提取所需信息:
// 公共拖拽结束处理逻辑 function handleDragEnd(evt) { // 取原列表、目标列表的标识和引用 const fromListName = evt.from.dataset.listName const fromListRef = evt.from.listRef const toListName = evt.to.dataset.listName const targetListRef = evt.to.listRef // Sortable已经自动修改了数组顺序,直接按新索引取被移动的对象即可 const movedItem = targetListRef[evt.newIndex] // 你需要的提交结构 const submitPayload = { item: movedItem.item, list: toListName } // 这里的movedItem、targetListRef都是原数据的直接引用,在Angular里修改会直接同步到视图 // 直接调用接口提交submitPayload即可 } // 初始化两个拖拽实例 Sortable.create(list1Container, { group: 'shared-list', onEnd: handleDragEnd }) Sortable.create(list2Container, { group: 'shared-list', onEnd: handleDragEnd })
Angular场景适配
在Angular组件中不需要手动查询DOM,通过@ViewChild拿到列表容器引用后直接绑定数据即可,示例代码如下:
组件模板
<div #arrayList1 class="drag-list"> <div *ngFor="let item of data.array_1" class="drag-item"> {{item.item}} </div> </div> <div #arrayList2 class="drag-list"> <div *ngFor="let item of data.array_2" class="drag-item"> {{item.item}} </div> </div>
组件类逻辑
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core'; import Sortable from 'sortablejs'; @Component({ selector: 'app-sort-demo', templateUrl: './sort-demo.component.html' }) export class SortDemoComponent implements AfterViewInit { // 业务数据源 data = { array_1: [{item:"#1"},{item:"#2"},{item:"#3"}], array_2: [{item:"#4"},{item:"#5"},{item:"#6"}] } @ViewChild('arrayList1') list1El!: ElementRef<HTMLElement>; @ViewChild('arrayList2') list2El!: ElementRef<HTMLElement>; ngAfterViewInit(): void { // 给DOM绑定关联数据 this.list1El.nativeElement.dataset.listName = 'array_1' this.list1El.nativeElement.listRef = this.data.array_1 this.list2El.nativeElement.dataset.listName = 'array_2' this.list2El.nativeElement.listRef = this.data.array_2 // 拖拽结束处理 const onDragEnd = (evt: Sortable.SortableEvent) => { const targetList = evt.to.listRef const targetListName = evt.to.dataset.listName const movedItem = targetList[evt.newIndex] // 直接操作movedItem、targetList都是对原数据的修改,Angular变更检测会自动同步 console.log('移动的元素:', movedItem, '目标列表:', targetListName) } // 初始化拖拽实例 Sortable.create(this.list1El.nativeElement, { group: 'shared-list', onEnd: onDragEnd }) Sortable.create(this.list2El.nativeElement, { group: 'shared-list', onEnd: onDragEnd }) } }
如果你用的是
ngx-sortablejs这类Angular封装库,逻辑完全一致,只需要把onEnd处理函数写到传入的配置对象中即可,事件对象的属性和原生Sortable完全相同。
内容的提问来源于stack exchange,提问作者Vlad Rovner
相关产品推荐
相关产品推荐

