【问题标题】:Angular Nested Drag and Drop / CDK Material cdkDropListGroup cdkDropList nestedAngular 嵌套拖放 / CDK 材质 cdkDropListGroup cdkDropList nested
【发布时间】:2021-07-24 00:51:11
【问题描述】:

我使用 CDK Material 拖放实用程序来创建一个启用拖放功能的表单编辑器。

它工作正常,但在 cdkDropListGroup 中嵌套 cdkDropList 不起作用。 我无法将任何内容拖到嵌套的下拉列表容器中。

<div class="container">
  <div class="row" cdkDropListGroup>
    <div class="col-2">
      <div id="toolbox" cdkDropList>
        ...
      </div>
    </div>
    <div class="col-10">
      <div id="formContainer" cdkDropList>
        ...
        <div class="row">
          <div class="col-md-6" cdkDropList>
            ... column 1 content
          </div>
          <div class="col-md-6" cdkDropList>
            ... column 1 content
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

【问题讨论】:

    标签: angular angular-material drag-and-drop angular-cdk


    【解决方案1】:

    我花了一些时间,但由于这些帖子的提示,我终于找到了解决方案:

    问题在于cdkDropListGroup 不支持嵌套下拉列表。您需要使用[cdkDropListConnectedTo] 绑定来连接下拉列表。

    但是,如果您仅将列表连接到 [cdkDropListConnectedTo] 绑定的数组,则列表顺序会影响放置行为。此外,嵌套下拉列表中的排序也不起作用。

    为避免这些问题,您需要创建一个服务,在拖动时查找正确的cdkDropList

    export class DragDropService {
      dropLists: CdkDropList[] = [];
      currentHoverDropListId?: string;
    
      constructor(@Inject(DOCUMENT) private document: Document) {}
    
      public register(dropList: CdkDropList) {
        this.dropLists.push(dropList);
      }
    
      dragMoved(event: CdkDragMove<IFormControl>) {
        let elementFromPoint = this.document.elementFromPoint(
          event.pointerPosition.x,
          event.pointerPosition.y
        );
    
        if (!elementFromPoint) {
          this.currentHoverDropListId = undefined;
          return;
        }
    
        let dropList = elementFromPoint.classList.contains('cdk-drop-list')
          ? elementFromPoint
          : elementFromPoint.closest('.cdk-drop-list');
    
        if (!dropList) {
          this.currentHoverDropListId = undefined;
          return;
        }
    
        this.currentHoverDropListId = dropList.id;
      }
    
      dragReleased(event: CdkDragRelease) {
        this.currentHoverDropListId = undefined;
      }
    }
    
    • register 向每个cdkDropList 使用的dropList 数组添加一个新的下拉列表。

    • dragMoved 确定鼠标指针下方的正确cdkDropList

    最好的办法是创建一个包含cdkDropList 的自己的组件。

    以下组件只是为了简单和演示目的。您不应该直接使用服务属性。

    <div
      *ngIf="container"
      cdkDropList
      [cdkDropListData]="container.controls"
      [cdkDropListConnectedTo]="dragDropService.dropLists"
      [cdkDropListEnterPredicate]="allowDropPredicate"
      (cdkDropListDropped)="dropped($event)"
    >
      <div
        *ngFor="let item of container.controls"
        cdkDrag
        [cdkDragData]="item"
        (cdkDragMoved)="dragMoved($event)"
        (cdkDragReleased)="dragReleased($event)"
      >
        Drag Content
      </div>
    </div>
    
    export class FormContainerComponent implements OnInit, AfterViewInit {
      @ViewChild(CdkDropList) dropList?: CdkDropList;
      @Input() container: IFormContainer | undefined;
    
      allowDropPredicate = (drag: CdkDrag, drop: CdkDropList) => {
        return this.isDropAllowed(drag, drop);
      };
    
      constructor(
        public dragDropService: DragDropService
      ) {}
      ngOnInit(): void {}
    
      ngAfterViewInit(): void {
        if (this.dropList) {
          this.dragDropService.register(this.dropList);
        }
      }
      dropped(event: CdkDragDrop<IFormControl[]>) {
        // Your drop logic
      }
    
      isDropAllowed(drag: CdkDrag, drop: CdkDropList) {
        if (this.dragDropService.currentHoverDropListId == null) {
          return true;
        }
    
        return drop.id === this.dragDropService.currentHoverDropListId;
      }
    
      dragMoved(event: CdkDragMove<IFormControl>) {
        this.dragDropService.dragMoved(event);
      }
    
      dragReleased(event: CdkDragRelease) {
        this.dragDropService.dragReleased(event);
      }
    }
    
    
    • 每当移动cdkDrag 时,dragMoved 都会确定正确的cdkDropList
    • 每当cdkDrag被释放时,重置确定的cdkDropList
    • 最重要的方法是isDropAllowed方法,设置为[cdkDropListEnterPredicate]="allowDropPredicate"cdkDropList
      • 如前所述,cdk 材料无法确定正确的下拉列表。
      • 如果 cdk 选择了错误的下拉列表,我们将通过返回 false 来禁止该下拉列表。在这种情况下,cdk 会自动选择下一个可能的cdkDropList,这是正确的:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-02
      • 2020-04-05
      • 2021-01-14
      • 2019-05-09
      • 2019-04-06
      • 2020-06-04
      • 2021-02-15
      相关资源
      最近更新 更多