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

Angular结合SortableJS拖拽放置后如何获取目标数组及元素信息

实现方案

SortableJS 本身和业务数据结构解耦,不会直接返回目标数组引用,只需要在初始化拖拽实例时给列表容器DOM绑定自定义关联数据,就能在onEnd事件里拿到所有需要的信息,完全满足Angular场景下直接操作数据对象、获取目标分组标识的需求。

核心逻辑说明

onEnd事件对象自带5个核心DOM属性,是所有信息的来源:

  • evt.item:被拖拽的DOM节点
  • evt.from:拖拽起始位置所属的列表容器DOM
  • evt.to:拖拽结束位置所属的列表容器DOM
  • evt.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 21:51:27