iOS13での連続したtouchstartイベント
今さらですが、iOS13になってからSafariで画面を連続タップした場合に、touchstartイベントが連続して発生しなくなりました。連続タップしても最初の一回のみtouchstartイベントが発生し、しばらく時間をおいてからでないと次のtouchstartイベントが発生しません。
この現象はhttps://forums.developer.apple.com/thread/125073などでも報告されています。
touchstartイベントが連続発生しないと、Webアプリケーションでダブルタップを検出したい時などで問題になります。
対策としてはいろいろと問題はあります(以下で説明)が、touchendイベントでpreventDefault()を呼び出すという手があります。
対策1(まだ不完全)
document.addEventListener('touchend', function (e) { e.preventDefault(); }, false);
これで〜iOS12と同じようにtouchstartが連続発生するようになります。
ただし、このままでは画面上の要素をクリックしてもclickイベントが発生しなくなるという別の問題が発生します。このため、touchendでイベント発行元の要素をチェックして、クリック可能な要素だった場合はpreventDefault()を呼ばないようにします。
対策2
document.addEventListener('touchend', function (e) { var tagName = e.target.tagName.toLowerCase(); if (tagName != 'a') { e.preventDefault(); } }, false);
上記対策では<a>タグがイベント発生元だった場合は、preventDefault()を呼ばないので、<a>タグをクリック時にclickイベントが発生するようになります。アプリケーションの内容によって、button,inputタグ等もpreventDefault()の対象外にすればいいと思います。これで、touchstartイベントの連続発生とclickイベントの発生を両立させることができました。
さらにタグの種類でまとめてではなく、要素ごとに個別にクリック可能指定をしたい場合は、以下のようにできます。
対策3
document.addEventListener('touchend', function (e) {
var tagName = e.target.tagName.toLowerCase();
if (!e.target.dataset.clickable &&
tagName != 'a') {
e.preventDefault();
}
}, false);
対策3 - クリック可能要素の指定
<div onclick="msg('clicked');" data-clickable="1">clickable node</div>
クリック可能にしたい要素にdata-clickable="1"属性を指定して、touchend内でこの属性をチェックするようにしています。
このようにtouchstartイベントが連続発生しない問題に対処することができます。
iOSのSafariはバージョン毎にころころと動作が変わるのでやっかいです。Chromeではほぼ動作は変わらないんですけどね。最近またこのあたりを触る機会があり、忘れかけていたので備忘録がてらまとめました。
投稿日:2020/05/28 23:00
タグ: Webアプリ JavaScript