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

