インタラクティブなDOM要素を使用して単一ページのJavascriptアプリを実行すると、 "_mouseover-mousemove-mousedown-mouseup-click
_"シーケンスがすべてafterイベントの "_touchstart-touchmove-touchend
_"シーケンスで発生することがわかりました。
touchstart
イベント中に「event.preventDefault()
」を実行すると、「_mouse*-click
_」イベントの発生を防ぐことができることもわかりました、しかしonlyそのとき、touchmove
とtouchend
の間ではありません。これは奇妙なデザインです。なぜなら、ユーザーがアイテムをドラッグまたはスワイプしたいのか、それとも単にタップ/クリックしただけなのかをtouchstart
中に把握することはまだ不可能だからです。
タイムスタンプに関連付けられた場所に「ignore_next_click」フラグを設定することになりましたが、これは明らかにあまりクリーンではありません。
誰かがこれを行うより良い方法を知っていますか、それとも何か不足していますか?
「クリック」は「_touchstart-touchend
_」シーケンス(つまり、「touchmove
」なし)として認識できますが、キーボード入力フォーカスなど、特定の状況でのみ発生する可能性があることに注意してください適切なclick
イベント。
touchend
イベントを防ぐだけです。要素に触れたときにブラウザがページをスクロールできるようにしますが、人工的なマウスイベントを発生させません。
element.addEventListener('touchend', event => {
event.preventDefault();
});
クロスプラットフォームの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();
}
他の場所で十分な解決策が見つからなかったので、私は自分で解決策を作りました:
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 = true
addEventListener
への呼び出しで、Webアプリ全体でコードをハッキングすることなく、ページ内のすべてのマウスイベントをスクープします。関数のドキュメントはこちらをご覧ください: https://developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener?redirectlocale=en-US&redirectslug=DOM%2Felement.addEventListener
編集:
この問題を処理するためのライブラリが改善されたので、代わりにFastclickなどを使用できます( https://github.com/ftlabs/fastclick )。
マウスとタッチの両方をサポートするデバイスをサポートする必要がある場合、別の解決策は、いずれかのマウスイベントを停止するキャプチャイベントリスナーを使用することです。
タッチイベントの情報(時間、位置、またはターゲット要素)は、別のキャプチャイベントリスナーに記録できます。
マウスのみのコードを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パーツが必要です。
'pointerwhatever'
の代わりに'mousewhatever'
を使用すると、現在のブラウザ(2019)では問題なく動作するようです。
つまり、すべてのエントリデバイスに同じコードを使用する way を発明しました。
このソリューションでは、存在する場合はPointerEvents
をリッスンし、存在する場合はTouchEvents
をリッスンし、他の2つが存在しない場合はMouseEvents
をリッスンできます。 Mobile Safariは引き続きtouchstart
とmousedown
の両方をレイズしますが、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');
});
}
モバイルWebアプリケーション用の高速ボタンの作成 が問題を解決します。
また、IE10 preventDefault()を使用しても、MSPointerDownイベントの後にゴースト/合成/エミュレートされたマウスイベントが停止しないため、真のクロスブラウザーソリューションの方が難しいことにも注意してください。
デバイスがタッチイベントをサポートしている場合、「クリック」、「マウスダウン」、または「マウスアップ」イベントで関数を終了しようとすることができます。
use.addEventListener("click",function(e){
// EXIT FUNCTION IF DEVICE SUPPORTS TOUCH EVENTS
if ("ontouchstart" in document.documentElement) return false;
// YOURMOUSEONLY CODE HERE
});