デバイスごとのイベント判定方法と問題点
タッチデバイスとポインティングデバイスでバインドするイベントを分別する際、いままでは以下のようにしてきました。
JavaScript
var event = 'ontouchstart' in window ? 'touchend' : 'click';
$('hoge').on(event, function());
しかし、この記述で判定すると、特定の環境でイベントの判別がうまくいかないのです。
- タッチディスプレイを搭載したPC
- Google Chrome
上記の組み合わせだと、event変数は必ずtrueを返します。
iOSやAndroidなどのスマートフォンOSでは、touchendとclickが時間差で発生するため (本当はもっといろんなイベントが発生していますが)、以下のようなことは当然できません。
JavaScript
$('hoge').on('touchend click', function());
新しい (?) イベント判定方法
そこで、最初に発生したイベント (touchstartやmousedownなど) を判別して、正しいイベントをバインドするようなスクリプトを作りました。
JavaScript
var event = {
all: 'mousedown touchstart pointerdown mouseenter mouseleave',
type: '',
start: '',
enter: '',
leave: '',
move: '',
end: ''
};
// イベント判定
event.check = function(e){
var _default = e.type;
event.start = _default;
event.move = _default === 'pointerdown' ? 'pointermove' : (_default === 'touchstart' ? 'touchmove' : 'mousemove');
event.end = _default === 'pointerdown' ? 'pointerup' : (_default === 'touchstart' ? 'touchend' : 'click');
event.enter = _default === 'pointerenter' ? _default : (_default === 'touchenter' ? _default : 'mouseenter');
event.leave = _default === 'pointerleave' ? _default : (_default === 'touchleave' ? _default : 'mouseleave');
};
event.on = function(type, elm, fn, delegate){
$(document).off(event.all, elm).on(event.all, elm, function(e){
e.preventDefault();
event.check(e);
if (fn != null) {
if (e.type === event.enter || e.type === event.leave) {
// mouseenter mouseleaveのとき、コールバック関数を即実行
fn(this, e);
} else {
if (type === 'bind') {
// jQuery $(element).on(event, func);
$(elm).off(event.end).on(event.end, function(e){
fn(this, e);
});
} else if (type === 'live') {
// jQuery $(document).on(event, element, func);
$(document).off(event.end, elm).on(event.end, elm, function(e){
fn(this, e);
});
} else if (type === 'delegate') {
// jQuery $(parentsElement).on(event, element, func);
$(delegate).off(event.end, elm).on(event.end, elm, function(e){
fn(this, e);
});
}
}
} else {
// 引数にコールバック関数が定義されていないときの処理
}
});
};
処理はそんなに難しいことをしていないはずなので、内容の説明は省きます。
実際の使い方は以下のようになります。
JavaScript
event.on(type, element, func, parentsElement);
var func = function(elm, e) {
if (e.type === event.end) {
//touchend、pointerup、clickのいずれかのときに実行
}
};
// example
event.on('bind', '.hoge', func);
event.on('live', '.hoge', func);
event.on('delegate', '.fuga', func, '.hoge');
これでどの (?) デバイスでも正しいイベントが自動的にバインドされるようになりました。
改善のアドバイスがございましたら、是非ご連絡ください。