2016-08-05 47 views
1

Ich habe Probleme mit Angular 2 und Touch-Geräten. Insbesondere wenn eine Komponente über NgFor gerendert wird und über den Bildschirm gezogen wird. Das Problem tritt auf, wenn während eines Berührungswiderlaufs (aufgrund eines externen Ereignisses, das die an den NgFor gebundene Daten aktualisiert, was in meiner App üblich ist) ein erneutes Rendern des NgFor auftritt. Die touchmove Ereignisse stoppen zu feuern, und Sie müssen Ihren Finger heben und legen Sie es wieder zurück, was eine schreckliche mobile Erfahrung ist. Dieses Problem tritt nicht auf, wenn Sie eine Maus verwenden.Gibt es eine Möglichkeit, DOM-Entfernung in Angular 2 RC5 zu verhindern?

Wesentlichen in meiner app höre ich für das touchstart Ereignis auf meine Komponente, zeigen ein anderes ‚DragComponent‘ über eine bedingte *ngIf="isDragging" (die nicht innerhalb der NgFor ist), und es wird über den Bildschirm auf der Grundlage der touchmove Ereignispositionsdaten bewegt .

Ich weiß, warum das passiert. Dies liegt an der Browser-Implementierung der Touch Spec. Normalerweise umkreife ich dieses Problem in vanilla js, indem ich das DOM-Element im Speicher belasse, bis das Ereignis touchend oder touchcancel ausgelöst wird. Angular steuert jedoch jetzt das DOM! Und sie entfernen das Element, solange es noch benutzt wird!

Schauen Sie sich diesen Plumer http://plnkr.co/edit/QR6WDzv6NxOmn6LXTngG?p=preview an, um mehr von einem Verständnis dessen zu bekommen, was ich versuche zu beschreiben. (Hinweis Touchscreen erforderlich oder verwenden Touch-Emulation in Chrome DevTools)

Ich habe auch ein Problem #9864 im Angular Repo geschaffen, aber bisher keine Antwort erhalten hatte. Ich verstehe, dass sie damit beschäftigt sind, sich auf das Finale vorzubereiten, aber meiner Meinung nach sollte dies vor dem Finale gelöst werden, da viele Benutzer Angular auf Touch-Geräten verwenden werden.

Ich würde mich über alle Tipps/Workarounds/Hacks freuen. Fühlen Sie sich frei, den Plunker mit einer Lösung zu aktualisieren.

Antwort

0

eine Abhilfe gefunden:

TouchEvents weiterhin tun eigentlich nach DOM Entfernung abzufeuern ABER sie sind nur an dem Knoten/Element gezielt, dass die ursprüngliche touchstart auf aufgetreten und nicht Blase (im Gegensatz zu Mausevents, das ist verwirrend!).

Also können wir nicht einfach @HostListener('touchmove', ['$event']) ausführen und erwarten, dass es mit der DOM-Entfernung funktioniert (da der Event-Listener an das äußere Komponentenelement angehängt ist). Wir müssen dynamisch Event-Listener zum Zielelement des Touchstart Ereignis hinzufügen, wie sie auftreten. Führen Sie anschließend eine Reinigung unter touchend oder touchcancel (oder ngOnDestroy()) durch.

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

Vergessen Sie nicht Renderer im Konstruktor zu injizieren (Import von @angular/core

Quelle https://plus.google.com/+RickByers/posts/GHwpqnAFATf