简体   繁体   English

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

[英]Is there a way to prevent DOM removal in Angular 2 RC5?

I'm having issues with Angular 2 and touch devices . 我遇到了Angular 2和触控设备的问题 In particular, when a Component is rendered via NgFor and is (touch) dragged about the screen. 特别是,当通过NgFor渲染Component并且(触摸)在屏幕上拖动时。 The issue arises if a re-render of the NgFor occurs during a touch drag (due to an external event updating the data bound to the NgFor, which is common in my app). 如果在触摸拖动期间发生重新渲染NgFor(由于外部事件更新绑定到NgFor的数据,这在我的应用程序中很常见),就会出现问题。 The touchmove events stop firing , and require you to lift your finger and place it back down again, which is a terrible mobile experience. touchmove事件停止发射 ,并要求您抬起手指并将其再次放下,这是一种糟糕的移动体验。 This issue does not occur if you use a mouse. 如果您使用鼠标不会发生此问题。

Essentially, in my app I listen for the touchstart event on my component, show another 'DragComponent' via a conditional *ngIf="isDragging" (which is not within the NgFor) and it is moved about the screen based on the touchmove event position data. 基本上,在我的应用程序中,我在组件上侦听touchstart事件,通过条件*ngIf="isDragging" (不在NgFor中)显示另一个'DragComponent',并根据touchmove事件位置在屏幕上移动数据。

I know why this happens. 我知道为什么会这样。 It's due to the browser implementation of the Touch Spec. 这是由于触摸规范的浏览器实现。 I normally code around this issue in vanilla js via keeping the DOM element in memory until the touchend or touchcancel event fire. 我通常在vanilla js中通过将DOM元素保留在内存中来解决这个问题,直到touchendtouchcancel事件。 However, Angular now controls the DOM! 但是,Angular现在控制着DOM! And they are removing the element while it's still in use! 当它仍在使用时,它们正在移除元素!

Check out this plunker http://plnkr.co/edit/QR6WDzv6NxOmn6LXTngG?p=preview to get more of an understanding of what I'm trying to describe. 查看这个plunker http://plnkr.co/edit/QR6WDzv6NxOmn6LXTngG?p=preview ,以便更好地了解我想要描述的内容。 (Note touchscreen required , or use Touch emulation in Chrome DevTools) 需要注意触摸屏 ,或在Chrome DevTools中使用Touch仿真)

I've also created an issue #9864 in the Angular repo, but haven't had any response. 我还在Angular回购中创建了一个问题#9864 ,但没有任何回复。 I understand they are busy getting ready for final, but in my opinion this should be solved before final as a lot of users will use Angular on touch devices. 我知道他们正忙着为最终做好准备,但在我看来,这应该在决赛前解决,因为很多用户会在触摸设备上使用Angular。

I'd appreciate any tips/workarounds/hacks. 我很感激任何提示/解决方法/黑客攻击。 Feel free to update the plunker with a solution. 随意用解决方案更新plunker。

Found a workaround: 找到了一个解决方法:

TouchEvents do actually continue to fire after DOM removal BUT they are only targeted at the node/element that the original touchstart occurred on and don't bubble (unlike MouseEvents, which is confusing!). TouchEvents做实际上继续DOM取出后开火, 他们只在节点/元素针对性原来touchstart发生在和不冒泡(不像MouseEvents,这是混乱!)。

So, we cant perform a simple @HostListener('touchmove', ['$event']) and expect it to work with DOM removal (as the event listener is attached to the outer component element). 这样,我们不能执行一个简单的@HostListener('touchmove', ['$event'])并期望它与DOM去除工作(作为事件监听器被附接到外部部件元素)。 We have to dynamically add event listeners to the target element of the touchstart event as they occur. 我们有事件侦听器,因为它们发生动态地添加到touchstart事件的目标元素 Then perform cleanup on touchend or touchcancel (or ngOnDestroy() ). 然后在执行清理touchendtouchcancel (或ngOnDestroy()

Soln: 溶液:

@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();

Don't forget to inject Renderer in the constructor (import from @angular/core 不要忘了注入Renderer在构造函数(进口@angular/core

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM