取消按键拖拽 Angular cdk Drag and Drop

Cancel drag on key press Angular cdk Drag and Drop

我正在一个应用程序中工作,该应用程序实现了 angular material CDK 的新拖放功能,我正在尝试取消按下 Esc 的元素的拖动事件,我的意思是,我开始拖动元素,但是如果我在拖动元素时按 Esc,它应该回到我开始拖动它的位置,到目前为止我还没有找到这样做的方法,有没有人知道我该怎么做。 cdk 文档中没有关于此任何想法的任何内容。我试着做这样的事情。

模板

<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
  <div class="example-box" *ngFor="let movie of movies" (cdkDragEnded)="onDragEnded($event)" cdkDrag>{{movie}}</div>
</div>

Ts分量

onDragEnded(event: CdkDragEnd) {
  console.log(event)
  event.source.element.nativeElement.style.transform = 'none';
  const source: any = event.source;
  source._passiveTransform = { x: 0, y: 0 };
}

但到目前为止没有成功。

您可以使用类似...

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
    if (event.code === 'Escape') {
        // call dragend event
    }
}

您可以使用以下方法将拖动的项目移动到某个位置:

event['source']['element']['nativeElement']['style']['transform'] = 'translate3d(0,0,0)';
event['source']['_dragRef']['_activeTransform'] = {x: 0, y: 0};
event['source']['_dragRef']['_passiveTransform'] = {x: 0, y: 0};

我也遇到这个问题很久了。最后我可以通过调度一个 mouseup 事件来修复它,该事件将充当用户释放鼠标的行为。

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
    if (event.key === 'Escape') {
        document.dispatchEvent(new Event('mouseup'));
    }
}

这是一个非常棘手的解决方案,并且有它的缺点。事实上,您并不是在取消拖动,而是在放下。这意味着如果您将鼠标悬停在 cdkDropList 上或其中一个处于活动状态,它将触发该列表的 cdkDropListDropped emmiter。您可以通过添加标志轻松解决问题。

private _canceledByEsq = false;

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
    if (event.key === 'Escape') {
        this._canceledByEsq = true;
        document.dispatchEvent(new Event('mouseup'));
    }
}

handleDrop() {
    if (!this._canceledByEsq) {
        // Do my data manipulations
    }
}

希望这对您有所帮助...:)

最好的方法是在 ESC 按键时调用 event.source._dragRef.reset();(如评论中提到的@AleRubis)。 现在的问题是从哪里可以得到 cdkDrag 事件(ESC 键事件)之外的 _dragRef,你可以在拖动开始时将它保存在这样的组件变量中。

组件:

cdkDragStarted = (event) => { this.dragRef = event.source._dragRef; }

模板:

<p cdkDrag (cdkDragStarted)="cdkDragStarted($event)"> Draggable paragraph </p>

这是一个使用 rxjs 的版本。它需要引用 CdkDrag 作为 ViewChild。不幸的是,因为没有 public 方法来停止在 DragRef 上拖动,您必须使用 dispatchEvent 作为结束拖动过程的唯一方法。

下面的例子有两部分。发生的事情是 ended 事件只能在开始后被监听,并且该监听实例可以被按下 escape 触发的主题停止。

  • 在 AfterViewInit 中,从 CdkDrag 指令创建了对 started EventEmitter 的订阅。
  • 开始事件后,切换到监听的流结束
  • 如果触发取消请求,流将由 takeUntil 运算符结束,并且将在指令上调用 reset() 以重置位置,并且 dispatchEvent() 将是用于停止拖动过程。
  • 否则,一旦触发结束事件,就会从 OP 调用 onDragEnded() 方法。
  • 除非有一些非常有趣的事情发生,否则 ended 事件每次开始最多只会触发一次,因此不需要额外的 take(1) .
private dragCancelRequest = new Subject();

ngAfterViewInit() {
  this.drag.started.pipe(
    switchMap(({ source }) => source.ended.pipe(
      takeUntil(this.dragCancelRequest.pipe(tap(() => {
        source.reset();
        document.dispatchEvent(new Event('mouseup'));
      })))
    )),
    tap(x => this.onDragEnded(x))
  ).subscribe();
}

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
  if (event.key === 'Escape') {
    this.dragCancelRequest.next();
  }
}