Angular 拖放 cdk...可滚动 div 中的自动滚动失去了 DROP ZONE

Ale*_*rdy 4 drag-and-drop autoscroll scrollable angular angular-cdk

因此,我正在沙箱中工作,以模仿我希望实现此拖放操作的应用程序的环境。很抱歉这么啰嗦,但我真的想确保正确解释问题,因为我已经看到了几篇关于此的旧帖子未回答或回答错误问题的问题。

简洁版本

  1. cdk dnd 不会自动滚动
  2. 做了我自己的自动滚动
  3. cdk dnd 滚动后不会掉落

诀窍是,cdk 拖放自动滚动功能似乎只能在与整个窗口大小相关的情况下开箱即用,或者如果它是带有溢出-y 的固定高度 div:滚动(这就是我正在尝试的)做),那么这需要在 cdkDropList 级别。不幸的是,由于我的应用程序的组件架构,目前这不是一个选项。

我编写了自己的自动滚动功能,该功能在拖动元素时根据鼠标的屏幕位置滚动 div,我可以正常工作,但最大的问题是,一旦 div 开始滚动,您就无法将项目拖放到元素中。列表。

这是我的父组件的 HTML(具有固定高度和溢出位置的 div)

<div #ScrollDiv style="height: 200px; width: 200px; overflow-y: scroll; padding: 5px;">
  <app-child (itemSelected)="itemSelection($event)"></app-child>
</div>
Run Code Online (Sandbox Code Playgroud)

这是带有 cdk 指令的子组件模板

   <div cdkDropList style="border: 2px solid purple;" (cdkDropListDropped)="drop($event)">
    <div cdkDrag [cdkDragData]="draggers" *ngFor="let item of draggers; let i = index"
            style="height: 30px; border: 2px solid blue; margin: 5px"
            (mousedown)="grabDrag()">
            {{item}}</div>   
    </div>
Run Code Online (Sandbox Code Playgroud)

此时,我可以在窗口中拖动,但自动滚动不起作用,因此我将自动滚动添加到父组件的 Type Script 文件中,更改 (mousemove) 上的滚动位置。对于开始向上/向下滚动的位置,这些值是基于我正在使用的页面上的硬编码。

import { Component, OnInit, ElementRef, ViewChild, AfterViewInit, ChangeDetectionStrategy } from '@angular/core';
import { Subscription, fromEvent } from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit  {
  title = 'drag-sizing';
  itemSelected = false;
  isScrolling = false;
  smoothScroll;
  scrollSpeed = 2;
  @ViewChild('ScrollDiv', {static: true}) public myScrollContainer: ElementRef;

ngAfterViewInit() {
  fromEvent(this.myScrollContainer.nativeElement, 'mousemove').subscribe((event: MouseEvent) => {
    if (this.itemSelected) {
      if (event.clientY < 150) {
        this.isScrolling = true;
        if (!this.smoothScroll) {
          this.smoothScroll = setInterval(() => {
            this.scrollUp();
          }, 10);
        }
      } else if (event.clientY > 300) {
        this.isScrolling = true;
        if (!this.smoothScroll) {
          this.smoothScroll = setInterval(() => {
            this.scrollDown();
          }, 10);
        }
      } else {
        clearInterval(this.smoothScroll);
        this.smoothScroll = undefined;
        this.isScrolling = false;
      }
    } else {
      clearInterval(this.smoothScroll);
      this.smoothScroll = undefined;
      this.isScrolling = false;
    }
  });
}
  scrollInner() {
    this.myScrollContainer.nativeElement.scrollTop += 2;
  }
  itemSelection(event) {
    this.itemSelected = event;
    if (!this.itemSelected) {
      clearInterval(this.smoothScroll);
      this.smoothScroll = undefined;
    }
  } 
  scrollUp() {
    if (this.isScrolling === true) {
      this.myScrollContainer.nativeElement.scrollTop -= this.scrollSpeed;
    }
  }

  scrollDown() {
    if (this.isScrolling === true) {
      this.myScrollContainer.nativeElement.scrollTop += this.scrollSpeed;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

子组件 TypeScript 发出项目正在被拖动并具有放置功能的信息

import { Component, OnInit, Input, ElementRef, ViewChild, AfterViewInit, Output, EventEmitter } from '@angular/core';
import { Subscription, fromEvent, BehaviorSubject, Subject } from 'rxjs';
import { CdkDragDrop, transferArrayItem, moveItemInArray } from '@angular/cdk/drag-drop';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements  AfterViewInit {
@Output() itemSelected = new EventEmitter<boolean>();

  itemIsSelected = false;
  draggers = ['item 0', 'item 1', 'item 2'...]

  ngAfterViewInit(): void {
    fromEvent(document, 'mouseup').subscribe(() => {
      this.itemIsSelected = false;
      this.itemSelected.emit(this.itemIsSelected);
  });
  }
  grabDrag() {
    this.itemIsSelected = true;
    this.itemSelected.emit(this.itemIsSelected);
  }
  drop(event: CdkDragDrop<any>) {
    console.log(event);
    moveItemInArray(this.draggers, event.previousIndex, event.currentIndex);
  }
}
Run Code Online (Sandbox Code Playgroud)

可能有一些我不使用一些失败尝试留下的东西

无论如何:我知道这很长,但我试图克服/弄清楚的主要行为是,当我拖动一个项目并滚动远离其初始视图端口中的一小部分数组时,cdk 拖放不再让我将项目放入数组的该位置...该项目仍然显示为“拖动”,但这让我相信它不再识别“拖放区域”

这是它的样子

小智 9

我认为解决方案可能是将cdkScrollable指令放入一个容器中,该容器内有 CDK 拖放组件。

  • 我已将 cdkScrollable 指令添加到可滚动(溢出)且可拖动列表所在的 div 元素。这解决了我在拖放时遇到的问题 (2认同)