一部のAndroid4.x端末でtouchstartでe.preventDefault()してもclickイベントが発火する
Galaxy Nexus(Android 4.2.2)とか他のAndroid4.1.2の端末で、e.preventDefault()しているにも関わらずclickイベントが呼ばれてしまうバグ?
背景
iScrollを使用しているサービスを一部のAndroid 4.2.2, 4.1.2端末で見ると、clickイベントが2回呼ばれてしまう。
どうも、iScroll内では、touchstartでe.preventDefault()して、touchendでclickイベントを発火しているのだが、デフォルトのclickと、iScrollのclickの二回呼ばれるらしい。
問題の端末 | Galaxy Nexus(android4.2.2) SO-01E(android4.1.2) Nexus S(android 4.1.2) |
対象のブラウザ | WebView, 標準ブラウザ (Chromeは問題なし) |
使用ライブラリ | iScroll 4 |
SO-04E(android4.1.2)、SC-04E(android4.2.2)や(4.0|2)系端末だと問題は起きない。もちろんiPhoneも。
コード
iScrollでは、touchendで、ダブルタップ検出のために250ms待ってからclickイベント発火させるみたいなことしているので、擬似的なのを実装。
<div id="click">ここをクリックすると</div> <div id="result"></div> <script> (function() { $('#click').on('touchstart', function(e) { e.preventDefault(); }).on('touchend', function() { $(this).trigger('click', ['clickされたで']); }).on('click', function(e, message) { message = message || 'こいつぁ。。。'; $('#result').append('<div class="child">' + message + '</div>'); }); })();
DEMO
スマホしか対応してないけど。
動作
PCとか普通のブラウザの場合
クリックすると「clickされたで」だけが表示。10回クリックすれば10個表示。
問題の端末
クリックすると「clickされたで」「こいつぁ。。。」の要素が表示される。
対策
どうしようかな…。
フラグ的な何かで管理するとか?
(function() { $('#click').on('touchstart', function(e) { e.preventDefault(); $.data(this, 'is_preventdefault', 1); }).on('touchend', function() { $(this).trigger('click', ['clickされたで']); }).on('click', function(e, message) { if ($.data(this, 'is_preventdefault') === 0) return; $.data(this, 'is_preventdefault', 0); message = message || 'こいつぁ。。。'; $('#result').append('<div class="child">' + message + '</div>'); }); })();
iScroll 5にするとか
iScroll5だと大丈夫なんだけど、コードが違いすぎて、何が原因でなおってるのか分からん…。
e.stopImmediatePropagation(), e.stopPropagation()あたりかなと思いつつ、上のコードに仕掛けてみたけどダメだった。
まとめ
e.preventDefault()をtouchstartで呼ぶと、clickイベントが発火しないって認識だったんだけど、違うのかな。他の端末では認識通りの挙動したけど、単純にブラウザによって違うだけ?それともバグ?
よく分からんが、こういうケースに出会いましたよってメモで。