web-dev-qa-db-ja.com

Javascriptを使用して、Mobile Safari / iPhoneでのタッチイベントからのマウスエミュレーションイベント(クリックなど)の防止

インタラクティブなDOM要素を使用して単一ページのJavascriptアプリを実行すると、 "_mouseover-mousemove-mousedown-mouseup-click_"シーケンスがすべてafterイベントの "_touchstart-touchmove-touchend_"シーケンスで発生することがわかりました。

touchstartイベント中に「event.preventDefault()」を実行すると、「_mouse*-click_」イベントの発生を防ぐことができることもわかりました、しかしonlyそのとき、touchmovetouchendの間ではありません。これは奇妙なデザインです。なぜなら、ユーザーがアイテムをドラッグまたはスワイプしたいのか、それとも単にタップ/クリックしただけなのかをtouchstart中に把握することはまだ不可能だからです。

タイムスタンプに関連付けられた場所に「ignore_next_click」フラグを設定することになりましたが、これは明らかにあまりクリーンではありません。

誰かがこれを行うより良い方法を知っていますか、それとも何か不足していますか?

「クリック」は「_touchstart-touchend_」シーケンス(つまり、「touchmove」なし)として認識できますが、キーボード入力フォーカスなど、特定の状況でのみ発生する可能性があることに注意してください適切なclickイベント。

41
Jaime Cham

touchendイベントを防ぐだけです。要素に触れたときにブラウザがページをスクロールできるようにしますが、人工的なマウスイベントを発生させません。

element.addEventListener('touchend', event => {
  event.preventDefault();
});
6
Finesse

クロスプラットフォームのHTML5/JSアプリを作成するときに同様の問題が発生しました。私にとっての唯一の本当の答えは、タッチイベントでpreventDefaultを実行し、実際にタッチステートを管理し、ロジックに従って自分でクリック、ドラッグなどのイベントを発生させることです。これは実際よりもはるかに困難に聞こえますが、模倣されたクリック/マウスイベントは、ほとんどのモバイルブラウザーで完全に機能します。

Clickと追加のmouseシーケンスはすべて、利便性(および互換性)のためにあります。私の経験則-それがあなたの便宜のためであるがそれが不便であるなら、それを殺すのが最善です。

入力ボックスに関しては、タッチエンドイベントのみが必要です。私はクリック/マウスイベントを殺しましたが、モバイルブラウザーに入力へのタッチに正しく応答させることができました。それでも問題が解決しない場合は、非入力のイベントのみを抑制するようにイベントハンドラーを変更できます。

function touchHandler(event) {
    var shouldIgnore = event.target != null 
          && ( event.target.tagName.toLowerCase() == "input" || event.target.tagName.toLowerCase() == "textarea" );

    if(!shouldIgnore) e.preventDefault();
}
5
Colin Godsey

他の場所で十分な解決策が見つからなかったので、私は自分で解決策を作りました:

   var isTouch = ('ontouchstart' in window);

   function kill(type){
     window.document.body.addEventListener(type, function(e){
       e.preventDefault();
       e.stopPropagation();
       return false;
     }, true);
   }

   if( isTouch ){
     kill('mousedown');
     kill('mouseup');
     kill('click');
     kill('mousemove');
   }

isTouchのチェックにより、マウス入力デバイスでは通常どおり動作しますが、Safari/iOSではエミュレートされたイベントが強制終了されます。コツはuseCapture = trueaddEventListenerへの呼び出しで、Webアプリ全体でコードをハッキングすることなく、ページ内のすべてのマウスイベントをスクープします。関数のドキュメントはこちらをご覧ください: https://developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener?redirectlocale=en-US&redirectslug=DOM%2Felement.addEventListener

編集:

この問題を処理するためのライブラリが改善されたので、代わりにFastclickなどを使用できます( https://github.com/ftlabs/fastclick )。

3
maxkfranz

マウスとタッチの両方をサポートするデバイスをサポートする必要がある場合、別の解決策は、いずれかのマウスイベントを停止するキャプチャイベントリスナーを使用することです。

  • タッチイベント後の遅延内
  • タッチイベントと同じ位置
  • タッチイベントと同じターゲット要素

タッチイベントの情報(時間、位置、またはターゲット要素)は、別のキャプチャイベントリスナーに記録できます。

2
Joel Richard

マウスのみのコードをWindow.matchesMedia関数でラップすることが、私が見つけた最もクリーンな方法です。

if (window.matchMedia('(hover: hover), (any-hover: hover), (-moz-touch-enabled: 0)').matches) {
    el.addEventListener('mouseover', ev => {
         // mouse handler, no simulated hover
    }
}

これは、シミュレートされたホバーを防ぐために機能しますが、シミュレートされたクリックも防ぐ可能性があります。

注:バージョン58以降のFirefoxでは、-moz-touch-enabledパーツが必要です。

2
robjtede

'pointerwhatever'の代わりに'mousewhatever'を使用すると、現在のブラウザ(2019)では問題なく動作するようです。

つまり、すべてのエントリデバイスに同じコードを使用する way を発明しました。

1
Rusca8

このソリューションでは、存在する場合はPointerEventsをリッスンし、存在する場合はTouchEventsをリッスンし、他の2つが存在しない場合はMouseEventsをリッスンできます。 Mobile Safariは引き続きtouchstartmousedownの両方をレイズしますが、touchstartのみをリッスンします。

if (window.PointerEvent) {                                  /* decent browsers */
    etouch.addEventListener('pointerdown', (e) => {
        console.log('pointerdown');
    });
}
else if (window.TouchEvent) {                               /* mobile Safari */
    etouch.addEventListener('touchstart', (e) => {
        console.log('touchstart');
    });
}
else {                                                      /* desktop Safari */
    etouch.addEventListener('mousedown', (e) => {
        console.log('mousedown');
    });
}
1
Brett Donald

モバイルWebアプリケーション用の高速ボタンの作成 が問題を解決します。

また、IE10 preventDefault()を使用しても、MSPointerDownイベントの後にゴースト/合成/エミュレートされたマウスイベントが停止しないため、真のクロスブラウザーソリューションの方が難しいことにも注意してください。

0
robocat

デバイスがタッチイベントをサポートしている場合、「クリック」、「マウスダウン」、または「マウスアップ」イベントで関数を終了しようとすることができます。

use.addEventListener("click",function(e){

  // EXIT FUNCTION IF DEVICE SUPPORTS TOUCH EVENTS
  if ("ontouchstart" in document.documentElement) return false;

  // YOURMOUSEONLY CODE HERE

});
0
Dennis Bohn