按键按下取消拖动 Angular cdk 拖放

11

我正在开发一个使用 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 };
}

但是到目前为止没有成功。


你解决了吗?谢谢,E。 - Eusthace
很遗憾,现在还没有... - Miguel Frias
1
为了将拖动的元素重置到其原始位置,现在您可以使用event.source._dragRef.reset();代替手动设置元素变换和source._passiveTransform - AleRubis
5个回答

8

我也长期面临这个问题。最终,我通过派发一个mouseup事件来解决它,该事件将作为用户释放鼠标的操作。

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

这是一种极其hacky的解决方案,它有自己的缺点。实际上,您并没有取消拖动,而是放弃了拖动。这意味着,如果您正在悬停在一个cdkDropList上或者其中一个处于活动状态,它将触发该列表的cdkDropListDropped发射器。您可以通过添加标志轻松解决此问题。

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
    }
}

希望这能帮到你... :)

2

您可以通过以下方式将拖动的项目移动到一个位置:

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};

1
最好的方法是在按下ESC键时调用event.source._dragRef.reset();(如@AleRubis在评论中提到的)。现在问题是,你可以从哪里获取_dragRef以外的cdkDrag事件(ESC键事件),当拖动开始时,你可以像这样将其保存在组件变量中。
组件: cdkDragStarted = (event) => { this.dragRef = event.source._dragRef; } 模板: <p cdkDrag (cdkDragStarted)="cdkDragStarted($event)"> 可拖动段落 </p>

对我没用。dragRef.reset() 似乎没有任何作用(在 Angular 9.1.X 中测试过)。因此,我更喜欢 @danizep 的解决方案。 - LittleWhite

1
这是使用rxjs的版本。它需要一个对CdkDrag的ViewChild引用。不幸的是,由于没有公共方法可以停止DragRef上的拖动,您必须使用dispatchEvent作为结束拖动过程的唯一方法。
以下示例分为两个部分。正在发生的是,在开始后只能侦听到ended事件,并且按下escape触发的subject可以停止该实例的侦听。
  • 在 AfterViewInit 中,创建了一个订阅来自 CdkDrag 指令的 started EventEmitter。
  • 开始事件后,流将切换到监听 ended 事件。
  • 如果取消请求被触发,则由 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();
  }
}

-2

你可以使用类似于...

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

1
好的,我可以检查按键,但是如何将拖动的元素重置到原始位置并取消拖动呢? - Miguel Frias
1
这是关于编程的内容,翻译成中文如下:问题比较泛化,即如何在拖动开始后取消拖动事件,并在鼠标按键按下时触发。 - Miguel Frias
在拖动元素时,您可以使用任何事件获取其实际位置,并在取消时使用此位置。如果您创建问题的堆栈跟踪,则会很有帮助。 - R. Viral
好的,问题是如何取消拖动事件,而不是如何将拖动的元素返回到原始位置,只有取消拖动事件,元素才能返回到原始位置,而不记住x或y位置,因此问题是如何在拖动开始后取消元素的拖动。 - Miguel Frias
这里有一个链接,您可以在代码中向我展示如何做到这一点,因为到目前为止,在那段代码中,您只是取消了鼠标事件,拖动事件仍在工作:[拖放]https://stackblitz.com/edit/angular-deufx5 - Miguel Frias
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接