1

我在使用 Angular 2 和触摸设备时遇到问题。特别是,当一个组件通过 NgFor 渲染并在屏幕上(触摸)拖动时。如果在触摸拖动期间发生 NgFor 的重新渲染(由于外部事件更新绑定到 NgFor 的数据,这在我的应用程序中很常见),则会出现问题。事件touchmove停止触发,并要求您抬起手指并再次将其放回原位,这是一种糟糕的移动体验。如果您使用鼠标,则不会发生此问题。

本质上,在我的应用程序中,我监听touchstart组件上的事件,通过条件*ngIf="isDragging"(不在 NgFor 中)显示另一个“DragComponent”,并根据touchmove事件位置数据在屏幕上移动。

我知道为什么会这样。这是由于 Touch Spec 的浏览器实现。我通常在 vanilla js 中通过将 DOM 元素保存在内存中直到touchendortouchcancel事件触发来解决这个问题。然而,Angular 现在控制着 DOM!他们正在移除仍在使用的元素!

查看这个 plunker http://plnkr.co/edit/QR6WDzv6NxOmn6LXTngG?p=preview以更多地了解我要描述的内容。(注意需要触摸屏,或者在 Chrome DevTools 中使用 Touch emulation)

我还在 Angular 存储库中创建了一个问题#9864,但没有任何回应。我知道他们正忙着为决赛做准备,但我认为这应该在决赛之前解决,因为很多用户会在触摸设备上使用 Angular。

我会很感激任何提示/解决方法/黑客。随时用解决方案更新 plunker。

4

1 回答 1

0

找到了解决方法:

TouchEvents 实际上在 DOM 移除后会继续触发,它们只针对原始touchstart发生的节点/元素并且不会冒泡(与 MouseEvents 不同,这是令人困惑的!)。

因此,我们不能执行一个简单的@HostListener('touchmove', ['$event'])操作并期望它与 DOM 删除一起工作(因为事件侦听器附加到外部组件元素)。我们必须在touchstart事件发生时动态地将事件侦听器添加到目标元素。然后对or (or )执行清理。touchendtouchcancelngOnDestroy()

索尔恩:

@HostListener('touchstart', ['$event'])
@HostListener('mousedown', ['$event'])
  dragStart(event) {
    if (event.touches) {    // avoid touch event loss issue
      this.removePreviousTouchListeners();    // avoid mem leaks      
      this.touchmoveListenFunc = this.renderer.listen(event.target, 'touchmove', (e) => { this.onDragMove(e); });
      this.touchendListenFunc = this.renderer.listen(event.target, 'touchend', (e) => { this.removePreviousTouchListeners(); this.onDragEnd(e); });
      this.touchcancelListenFunc = this.renderer.listen(event.target, 'touchcancel', (e) => { this.removePreviousTouchListeners(); this.onDragEnd(e); });
    }
   ...
}

removePreviousTouchListeners() {
    if (this.touchmoveListenFunc !== null)
      this.touchmoveListenFunc();             // remove previous listener
    if (this.touchendListenFunc !== null)
      this.touchendListenFunc();              // remove previous listener
    if (this.touchcancelListenFunc !== null)
      this.touchcancelListenFunc();           // remove previous listener

    this.touchmoveListenFunc = null;
    this.touchendListenFunc = null;
    this.touchcancelListenFunc = null;
  }

 @HostListener('mousemove', ['$event'])
  // @HostListener('touchmove', ['$event'])    // don't declare this, as it is added dynamically
  onDragMove(event) {
    ...   // do stuff with event
  }

@HostListener('mouseup', ['$event'])
  // @HostListener('touchend', ['$event'])     // don't use these as they are added dynamically
  // @HostListener('touchcancel', ['$event']) // don't use these as they are added dynamically
  onDragEnd(event) {
    ...  // do stuff
  }

 ngOnDestroy() {
   this.removePreviousTouchListeners();

不要忘记Renderer在构造函数中注入(从@angular/core

来源https://plus.google.com/+RickByers/posts/GHwpqnAFATf

于 2016-08-15T01:41:04.517 回答