blog @arfyasu

プログラミングとか趣味のこととか

開閉可能な入力フォームが iOS で動作しなかった時の対処メモ

はじめに

開閉する入力フォームを作ったところ、PCでは正常に動作する開閉動作が iOSSafari で動きませんでした。
調査した所、開閉アイコンをクリックした際のイベントが発火していなかったことが原因でした。

調査に結構時間がかかったので、メモとして残しておきます。

問題のコード

該当部分を抜き出してJSFiddle で作成してみました。
原因分かりますか?

原因

原因をググっていると、以下のページに辿り着きました。

iOSにおけるclickイベントの発生条件まとめ - hifive

原因箇所を引用します。

div、span、strongなどHTMLで通常クリック対象になるような意味を持たない要素に対しては、通常clickイベントは発生しない

このため、documentあるいはbody要素にclickイベントハンドラをバインドしてもイベントハンドラは動作しない

今回、span タグを使っていたのでビンゴでした。
対策も幾つかページに記載されていました。

対策1. イベント登録をクラス要素に変更

対策箇所を引用します。

ただし、bodyより下の子孫要素にイベントハンドラをセットした場合、その要素及びその子孫要素ではclickイベントが発生するようになる

ということで、以下のように親クラスにイベントを登録することで動作するようになりました。

$('.e_form_title').on('click', '.glyphicon-chevron-down', function(e) {
  this.showInputArea(e);
}.bind(this));
$('.e_form_title').on('click', '.glyphicon-chevron-up', function(e) {
  this.hideInputArea(e);
}.bind(this));

これで、動作するようになりました!だがしかし、、、

クリックイベント発火するまで300ms程度のタイムラグが有るみたいですね。
タップしてから開閉するまでに間があって、正直嫌な感じです。

対策2. click イベントを touchstart イベントに変更

またまた、引用します。

"click"イベントではなく、"touchstart"イベントに対してイベントをバインドした場合、ハンドラは動作します。

click イベントと touchstart イベントが両方発火しないよう、touchstart が利用できる場合のみ touchstart で動作するようにするのが良さそうです。

touchstart が利用可能かは、以下のコードで判定できました。

('ontouchstart' in window)

[JS] タップイベントが実装されているのかを調べる方法(2つ) - YoheiM .NETより

これを考慮して修正したのが、以下のコードです。
これで、スマホでもいい感じで動くようになりました。

var eventName = ('ontouchstart' in window) ? 'touchstart' : 'click';
$(document).on(eventName, '.glyphicon-chevron-down', function(e) {
  this.showInputArea(e);
}.bind(this));
$(document).on(eventName, '.glyphicon-chevron-up', function(e) {
  this.hideInputArea(e);
}.bind(this));

まとめ

BtoB の Web サービスの開発が主だったので、スマホを意識した開発経験がなくはまりました。
ググると同じようなページがあって、結構有名な現象みたいですね。

いずれにしても、本当に助かりました。
こういう情報があることに感謝ですね。

参考

http://qiita.com/38kun/items/ce6a26c9c59612e6f515