有没有办法防止在Angular 2 RC5中删除DOM?

时间:2016-08-05 01:00:48

标签: javascript dom angular touch ngfor

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

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

我知道为什么会这样。这是由于触摸规范的浏览器实现。我通常在vanilla js中通过将DOM元素保留在内存中来解决此问题,直到touchendtouchcancel事件触发为止。但是,Angular现在控制着DOM!当它仍在使用时,它们正在移除元素!

查看此弹药http://plnkr.co/edit/QR6WDzv6NxOmn6LXTngG?p=preview,以便更好地理解我试图描述的内容。 (请注意需要触摸屏,或在Chrome DevTools中使用触摸模拟)

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

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

1 个答案:

答案 0 :(得分:0)

找到了解决方法:

TouchEvents在删除DOM后确实继续触发它们仅针对发生原始touchstart的节点/元素并且不会冒泡(与MouseEvents不同,这是混乱!)。

因此,我们无法执行简单的@HostListener('touchmove', ['$event'])并期望它可以与DOM删除一起使用(因为事件侦听器附加到外部组件元素)。我们必须动态将事件监听器添加到 touchstart 事件的目标元素中。然后在touchendtouchcancel(或ngOnDestroy())上执行清理。

溶液:

@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