1

Angular 2 とtouch devicesに問題があります。特に、コンポーネントが NgFor を介してレンダリングされ、画面上で (タッチ) ドラッグされる場合。この問題は、タッチ ドラッグ中に NgFor の再レンダリングが発生した場合に発生します (NgFor にバインドされたデータを更新する外部イベントが原因で、これは私のアプリでは一般的です)。イベントのtouchmove発生が停止し、指を離して再び下に置く必要があり、これはひどいモバイル エクスペリエンスです。マウスを使用する場合、この問題は発生しません。

基本的に、私のアプリではtouchstart、コンポーネントのイベントをリッスンし、条件 (NgFor 内にはない) を介して別の「DragComponent」を表示し、イベント位置データ*ngIf="isDragging"に基づいて画面上を移動します。touchmove

なぜこれが起こるのか知っています。これは、Touch Spec のブラウザー実装によるものです。touchend通常、またはtouchcancelイベントが発生するまでDOM要素をメモリに保持することにより、バニラjsでこの問題を回避するコーディングを行います。しかし、Angular が DOM を制御するようになりました! そして、彼らはまだ使用中の要素を削除しています!

このプランカーhttp://plnkr.co/edit/QR6WDzv6NxOmn6LXTngG?p=previewをチェックして、私が説明しようとしていることをより理解してください。(タッチスクリーンが必要であることに注意するか、Chrome DevTools でタッチ エミュレーションを使用します)

また、Angular リポジトリでイシュー#9864を作成しましたが、応答がありません。最終版の準備で忙しいのは理解していますが、多くのユーザーがタッチ デバイスで Angular を使用するため、最終版の前に解決する必要があると思います。

ヒント/回避策/ハックをいただければ幸いです。プランカーを解決策で自由に更新してください。

4

1 に答える 1

0

回避策を見つけました:

TouchEvents は実際には DOM の削除後も発生し続けます、オリジナルが発生したノード/要素のみを対象としており、touchstartバブルしません (MouseEvents とは異なり、混乱します!)。

そのため、簡単に実行でき@HostListener('touchmove', ['$event'])ず、DOM の削除で機能することを期待できません (イベント リスナーが外側のコンポーネント要素に関連付けられているため)。touchstartイベントのターゲット要素が発生すると、イベント リスナーを動的に追加する必要があります。次に、または(または) に対してクリーンアップを実行します。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 に答える