Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

[jQuery] click / touch / pointer イベントを完全に制御する

More than 5 years have passed since last update.

デバイスごとのイベント判定方法と問題点

タッチデバイスとポインティングデバイスでバインドするイベントを分別する際、いままでは以下のようにしてきました。

JavaScript
var event = 'ontouchstart' in window ? 'touchend' : 'click';

$('hoge').on(event, function());

しかし、この記述で判定すると、特定の環境でイベントの判別がうまくいかないのです。

  1. タッチディスプレイを搭載したPC
  2. 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');

これでどの (?) デバイスでも正しいイベントが自動的にバインドされるようになりました。

改善のアドバイスがございましたら、是非ご連絡ください。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away