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

Angular CDK:解决父子元素跨父容器拖拽列表的实现问题

解决方案:实现子元素跨父容器拖拽

要让子项能在不同父容器的子列表间拖拽,需调整容器连接关系、容器引用获取并修正数据源绑定,具体修改如下:

1. 修正父容器的数据源绑定

HTML中父容器绑定的[cdkDropListData]="parent"与TS定义的数据源parentList不匹配,先修正:

<ul
  cdkDropList
  [cdkDropListData]="parentList" <!-- 改为parentList -->
  class="example-list"
  (cdkDropListDropped)="drop($event)"
>

2. 获取所有子容器的引用

在组件中通过@ViewChildren获取所有子级CdkDropList实例,用于建立跨容器连接:

import { ViewChildren, QueryList, AfterViewInit } from '@angular/core';
import { CdkDropList } from '@angular/cdk/drag-drop';

// ...

@ViewChildren('childList') childLists!: QueryList<CdkDropList>;
childListIds: string[] = [];

ngAfterViewInit() {
  this.childListIds = this.childLists.map(list => list.id);
  // 监听子列表动态变化,更新ID数组(适配父项增减场景)
  this.childLists.changes.subscribe(() => {
    this.childListIds = this.childLists.map(list => list.id);
  });
}

3. 让子容器连接所有其他子容器

修改子容器的cdkDropListConnectedTo,使其指向所有子容器的ID数组:

<ul
  #childList="cdkDropList"
  *ngIf="item.children"
  [cdkDropListData]="item.children"
  cdkDropList
  [cdkDropListConnectedTo]="childListIds" <!-- 绑定所有子容器ID -->
  (cdkDropListDropped)="drop($event)"
>

4. 优化拖拽数据传递(可选)

将子项的cdkDragData绑定为子项本身,方便后续扩展处理:

<li
  *ngFor="let subItem of item.children"
  cdkDrag
  [cdkDragData]="subItem" <!-- 绑定当前子项 -->
>
  {{subItem.name}}
</li>

完整修改后代码

HTML模板

<div cdkDropListGroup>
  <ul
    cdkDropList
    [cdkDropListData]="parentList"
    class="example-list"
    (cdkDropListDropped)="drop($event)"
  >
    <li *ngFor="let item of parentList" cdkDrag>
      {{item.name}}
      <ul
        #childList="cdkDropList"
        *ngIf="item.children"
        [cdkDropListData]="item.children"
        cdkDropList
        [cdkDropListConnectedTo]="childListIds"
        (cdkDropListDropped)="drop($event)"
      >
        <li
          *ngFor="let subItem of item.children"
          cdkDrag
          [cdkDragData]="subItem"
        >
          {{subItem.name}}
        </li>
      </ul>
    </li>
  </ul>
</div>

Component.ts

import { Component, ViewChildren, QueryList, AfterViewInit } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem, CdkDropList } from '@angular/cdk/drag-drop';

@Component({
  selector: 'cdk-drag-drop-connected-sorting-example',
  templateUrl: './cdk-drag-drop-connected-sorting-example.html',
  styleUrls: ['./cdk-drag-drop-connected-sorting-example.css'],
})
export class CdkDragDropConnectedSortingExample implements AfterViewInit {
  parentList: any[] = [
    { id: 1, name: 'Parent 1', children: [{ id: 11, name: 'Child 1' }, { id: 12, name: 'Child 2' }] },
    { id: 2, name: 'Parent 2', children: [{ id: 21, name: 'Child 3' }, { id: 22, name: 'Child 4' }] }
  ];

  @ViewChildren('childList') childLists!: QueryList<CdkDropList>;
  childListIds: string[] = [];

  ngAfterViewInit() {
    this.childListIds = this.childLists.map(list => list.id);
    this.childLists.changes.subscribe(() => {
      this.childListIds = this.childLists.map(list => list.id);
    });
  }

  drop(event: CdkDragDrop<any[]>) {
    if (event.previousContainer === event.container) {
      moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
    } else {
      transferArrayItem(
        event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex
      );
    }
  }
}

关键原理

  • @ViewChildren('childList')批量获取所有子容器实例,提取ID组成可连接的容器数组。
  • [cdkDropListConnectedTo]="childListIds"让每个子容器与其他所有子容器建立连接,允许跨容器拖拽。
  • cdkDropListGroup辅助管理容器关系,结合显式指定的connectedTo实现精准拖拽控制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 17:57:36