「touchstart」イベントと「click」イベントをバインドし、両方に応答しない方法は?


198

私はさまざまなデバイスで動作する必要があるモバイルWebサイトに取り組んでいます。現在頭痛の種となっているのはBlackBerryです。

キーボードクリックとタッチイベントの両方をサポートする必要があります。

理想的には次のように使用します:

$thing.click(function(){...})

しかし、私たちが遭遇している問題は、これらのブラックベリーデバイスの一部には、タッチの時間からクリックをトリガーするまでの非常に迷惑な遅延があるということです。

解決策は、代わりにtouchstartを使用することです。

$thing.bind('touchstart', function(event){...})

しかし、どのようにして両方のイベントをバインドするのですか?キーボードデバイスのクリックイベントはまだ必要ですが、タッチデバイスを使用している場合は、もちろんクリックイベントの発生を望まないでください。

おまけの質問:これを行う方法はありますか?さらに、タッチスタートイベントさえもないブラウザーに対応できますか?これを調査したところ、BlackBerry OS5はタッチスタートをサポートしていないようです。そのため、そのブラウザーのクリックイベントにも依存する必要があります。

補遺:

おそらくより包括的な質問は次のとおりです。

jQueryを使用して、同じバインディングでタッチ操作とマウス操作の両方を処理することは可能/推奨されますか?

理想的には、答えはイエスです。そうでない場合は、いくつかのオプションがあります。

1)WURFLを使用してデバイス情報を取得するため、独自のデバイスマトリックスを作成できます。デバイスに応じて、タッチスタートまたはクリックを使用します。

2)JSを介してブラウザーでタッチサポートを検出します(これについてさらに調査する必要がありますが、それは実行可能のようです)。

ただし、それでも1つの問題が残ります。両方をサポートするデバイスはどうでしょうか。私たちがサポートする一部の電話(つまり、NokiasとBlackBerries)は、タッチスクリーンキーボードの両方を備えています。それで、そのようなことは私を元の質問に完全に戻します...両方を一度にどうにかしてどうにかして許可する方法はありますか?


2
touchstartとtouchendにバインドし、タッチロジックと一緒に独自のクリックロジックを記述する方がよいでしょう。タッチに関する知識がないため、組み込みのクリックコールバック。
Justin808 2011

私がフォローしているのかよくわかりません、ジャスティン。タッチスタートイベントとクリックイベントの両方がまだバインドされていませんか?
DA。

@DA-いいえ、.click()コールバックにまったくバインドしません。いくつかのsudoコードで回答を書いてみます。実際のコードを書くのに便利なタッチデバイスはありません:)
Justin808

ああ、でも明確にするために、非タッチデバイスでこのサイトにアクセスする人がいるので、クリックイベントがまだ必要です。
DA。

2
を使用して.bind('touchstart mouseup')解決します(以下のコメントのいずれかに基づく)
oriadam

回答:


135

更新:マウスとタッチのどちらかを選択する代わりに「ポインター」イベントにバインドできるjQuery ポインターイベントポリフィルプロジェクトを確認してください。


両方にバインドしますが、フラグを作成して、関数が100ミリ秒ごとに1回だけ実行されるようにします。

var flag = false;
$thing.bind('touchstart click', function(){
  if (!flag) {
    flag = true;
    setTimeout(function(){ flag = false; }, 100);
    // do something
  }

  return false
});

7
うーん...それはハックを感じますが、それはうまくいくかもしれません。キャッチは、これらのデバイスのいくつかでは、顕著な遅延です...おそらくほぼ1秒です...これは、より高速なデバイスでは他の人を困らせるでしょう。
DA。

15
代わりに使用するclickには、それを変更しmousedown...多分、長い遅延が間の違いがあるmousedownmouseupどの方法でclick決定されます。
Mottie

7
これは私が行ったソリューションです。ありがとう!私がしtouchendていることは、のクラスを適用してアイテムにフラグを立てることですtouched。これは、クリックイベントが呼び出される前に発生します。次に、最初にそのクラスの存在を確認するクリックイベントを追加します。存在する場合は、タッチイベントが発生したと想定し、次の対話のためにクラス名を削除してそれを「リセット」する以外、クリックでは何もしません。クラスがそこにない場合、キーボードを使用して項目をクリックし、そこから関数をトリガーしたと想定します。
DA。

7
ほとんどの電話ブラウザではクリックイベントで300ミリ秒の遅延があることに注意してください。遅延を少なくとも300に増やす必要があります。300 ミリ秒の遅延の問題に関するこの記事を参照してください。これは基本的に、ほとんどのWebサイトが大きなデスクトップ画面で表示するように設計されていた初期のiPhone時代で非常に重要な機能であった「ダブルクリックしてズーム」機能を有効にするためです。
2018

12
この質問は、現時点で10万回近く表示されています。これは、非常に一般的な使用例/問題のようです。ただし、この回答と、この質問および類似の質問に対する他の回答はすべて、ハッキリしているようです。Googleのソリューションは、他のソリューションよりも徹底的に考え抜かれていますが、より堅牢なハックにすぎないようです。クリックハンドラーのような単純なものの場合、ソリューションは単純である必要があります。この問題のハック以外の解決策を見つけた人はいませんか?
jinglesthula 14

73

これは私が「作成」した修正であり、GhostClickを取り出してFastClickを実装しています。自分で試してみて、うまくいったかどうかをお知らせください。

$(document).on('touchstart click', '.myBtn', function(event){
        if(event.handled === false) return
        event.stopPropagation();
        event.preventDefault();
        event.handled = true;

        // Do your magic here

});

2
helgatheviking:jsbin.com/ijizat/25 JavaScriptには、上記を組み込んだTouchClickという関数があります。
マットパーキンス2013

5
この質問に対するすべての回答の中で、私はこの方法を非常に好みます。それは、a)デバイス機能のテストではなく、b)setTimeoutを使用しないためです。私の経験では、setTimeoutを使用するこのような問題の解決策はほとんどの場合に機能しますが、イベントのタイミングはかなり恣意的で、デバイス固有です。
itsmequinn 2013

7
これは機能しません。無名関数で「イベント」を渡すことにより、その関数内のローカルオブジェクトになるため、イベントがトリガーされるたびevent.handledに等しくなりundefinedます。これが解決策です:を使用してターゲット要素自体に 'handled'フラグを設定しjQuery.data()ます。
thdoan 2015

3
あなたは持っているevent.stopPropagation();event.preventDefault();私の理解(およびテスト)からのイベントはこれだけで一度焼成することができます。なぜチェックするのif(event.handled !== true)ですか?私にとってそれは必要ではないか、何かを逃していますか?
nbar 2016年

2
event.handled値をチェックすべきではありませんtrueか?私の知る限りでは、そうではありませんfalse。最初はで始まりundefined、次にに設定されているかどうかを確認しtrueます。
ACJ 2017年

49

あなたはこのようなことを試すことができます:

var clickEventType=((document.ontouchstart!==null)?'click':'touchstart');
$("#mylink").bind(clickEventType, myClickHandler);

5
これの問題は、ユーザーがやっていることではなく、デバイスの機能をテストしていることだと思いますよね?課題は、キーボードも(両方を使用できるように)持つタッチデバイスをサポートする必要があることです
DA。

8
これは良い考えではありません-マウスを使用しているときに、タッチスクリーンとマウスを使用しているユーザーのイベントを中断します(タッチスクリーンを使用したラップトップが一般的になりつつあります)。
クリスチャンJ.

1
これに関連した優秀な記事:hacks.mozilla.org/2013/04/...
ルークメリア

これが使用されている場合、Windows 8は常に「touchstart」イベントをワイヤリングします。これは、このOSの「ontouchstart」が「true」を返すためです。したがって、コードが真のタッチスクリーンデバイスでのみ実行されるのでない限り、おそらく最良の答えではありませんが、そうであれば、チェックはまったく必要ありません。
Neil Monroe

タッチスクリーンを備えたラップトップでは、ユーザーはこのコードを使用してクロム(少なくともクロム46)で何かをクリックすることはできません。IE 11でも動作するようです。
David Sherret、2015年

42

通常、これも機能します。

$('#buttonId').on('touchstart click', function(e){
    e.stopPropagation(); e.preventDefault();
    //your code here

});

8
@Jonathanは間違っています。新しいjQueryバージョンを使用している場合です。Liveはバージョン1.7で廃止されました。
マイクバーウィック2013年

私はまた、e.stopPropagation()を試してみました(そして、私の考えではなく、他の場所で読みました)。e.preventDefault(); (私にとっては)ほとんど機能しますが、実際には20回は予測どおりに機能しますが、1回は機能しないので、後で気づきました。ここを見てください:stackoverflow.com/questions/25671053/…その問題についてのコメントに感謝します!
Garavani、2014

@MikeBarwickコメントを説明してもらえますか、それを説明するリンクを教えてください。前もって感謝します。
Billal Begueradj 2016

22

イベント関数のreturn false;最後に追加するだけでon("click touchstart")この問題を解決できます。

$(this).on("click touchstart", function() {
  // Do things
  return false;
});

.on()の jQueryドキュメントから

falseイベントハンドラーから戻ると、とが自動的に呼び出さevent.stopPropagation()event.preventDefault()ます。false値もの省略形として、ハンドラのために渡すことができますfunction(){ return false; }


2
両方の機能を備えたデバイスで1回だけ発火します-これは私にとって最もクリーンでハッキングの少ないソリューションのようです
Adam Cooper

私にとって最も効果的で、実際にその理由を理解しました。
Amir5000

これの欠点はありますか?なぜそのような単純な解決策が広く知られていないのですか?
ESR

10

私も同じようなことをしなければなりませんでした。ここに私のために働いたものの簡単なバージョンがあります。タッチイベントが検出された場合、クリックバインディングを削除します。

$thing.on('touchstart click', function(event){
  if (event.type == "touchstart")
    $(this).off('click');

  //your code here
});

私の場合、クリックイベントは<a>要素にバインドされていたため、クリックバインドを削除してクリックイベントを再バインドする必要があり、<a>要素のデフォルトアクションが妨げられました。

$thing.on('touchstart click', function(event){
  if (event.type == "touchstart")
    $(this).off('click').on('click', function(e){ e.preventDefault(); });

  //your code here
});

これがそのまま機能することを望みますが、機能しません。$(this)は、あなたが思っていることを指していない。
Dave Lowerre 14

8

私は次の方法で成功しました。

イージーピージー...

$(this).on('touchstart click', function(e){
  e.preventDefault();
  //do your stuff here
});

4
クリックとタッチスタートの両方を登録するデバイスで2回起動しませんか?
DA。

8
すみません、あなたに連絡しました。はい、そうです。タッチするとタッチスタートイベントとクリックイベントも生成されます。これはゴーストクリックと呼ばれます。Googleはそのためのソリューションを実装しました。簡単ではないかもしれませんが、完全に機能します。こちらがリンクです。code.google.com/mobile/articles/fast_buttons.html#ghost
Hasanavi

2
ささいなことかもしれませんが、eパラメーターが欠落していますfunction()
ProblemsOfSumit

@Hasanaviこれは素晴らしい修正でしたが、.onを使用してより良い結果を見つけました
Neil

1
@Neilに感謝します。はい、.onを使用することをお勧めします。将来のバージョンで削除される可能性があるためです。私の例をバインドからオンに変更しました。
ハサナビ、

5

私はベストプラクティスが今使用することだと信じています:

$('#object').on('touchend mouseup', function () { });

タッチエンド

touchendイベントは、タッチポイントがタッチサーフェスから削除されると発生します。

touchendイベントはマウスイベントをトリガーしませ


マウスアップ

マウスポインタが要素の上にあり、マウスボタンが離されると、mouseupイベントが要素に送信されます。すべてのHTML要素がこのイベントを受け取ることができます。

mouseupイベントは、タッチイベントをトリガーしませ

$('#click').on('mouseup', function () { alert('Event detected'); });
$('#touch').on('touchend', function () { alert('Event detected'); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 id="click">Click me</h1>
<h1 id="touch">Touch me</h1>


編集(2017)

2017年現在、ブラウザーはChromeから始まり、クリックイベントを作成するための手順を実行しています .on("click")クリックリクエストのタップイベントによって生成される遅延を排除することにより、マウスとタッチの両方で互換性を高めるための。

これにより、クリックイベントだけを使用するように戻すことが、最も簡単な解決策になると結論付けられます。

これが実用的かどうかを確認するためのクロスブラウザーテストはまだ行っていません。


これは有望であるように思えたので、いじくり回しましmouseupたが、特に従来のマウスの代わりにトラックパッドを使用すると、最終的に予期しない結果になることがわかりました。
skybondsor 2017

4

通常、デフォルトのタッチAPIと非タッチ(クリック)APIを混在させたくありません。タッチの世界に移動すると、タッチ関連の機能のみを扱う方が簡単になります。以下は、あなたがやりたいことをする疑似コードです。

touchmoveイベントで接続して位置を追跡する場合は、doTouchLogic関数に項目を追加して、ジェスチャーなどを検出できます。

var touchStartTime;
var touchStartLocation;
var touchEndTime;
var touchEndLocation;

$thing.bind('touchstart'), function() {
     var d = new Date();
     touchStartTime = d.getTime();
     touchStartLocation = mouse.location(x,y);
});

$thing.bind('touchend'), function() {
     var d = new Date();
     touchEndTime= d.getTime();
     touchEndLocation= mouse.location(x,y);
     doTouchLogic();
});

function doTouchLogic() {
     var distance = touchEndLocation - touchStartLocation;
     var duration = touchEndTime - touchStartTime;

     if (duration <= 100ms && distance <= 10px) {
          // Person tapped their finger (do click/tap stuff here)
     }
     if (duration > 100ms && distance <= 10px) {
          // Person pressed their finger (not a quick tap)
     }
     if (duration <= 100ms && distance > 10px) {
          // Person flicked their finger
     }
     if (duration > 100ms && distance > 10px) {
          // Person dragged their finger
     }
}

それが問題の核心だと思います。1つのコードベースで両方のモデルをサポートすることは理にかなっていますか。いくつかのシナリオで質問を更新します。
DA。

1
「一般的に、デフォルトのタッチと非タッチを混在させたくない」これに同意します。問題は、キーボードを使ったタッチデバイスを作り続けていることです。これは、私たちの開発者にとって頭痛の種です。
DA。

最初の最後のjs決定タッチまたはタッチなしのほうがはるかに簡単であることに同意します。なんて簡単な世界でしょう。しかし、これらののろわれたデバイスは、賢明なクリックとタッチについてこれは何ですか?それらのためにそれらすべての頭痛を抱えることは価値がありますか?これは私が問う未来ですか?
Garavani

関数の複数の定義を持つという考えは好きではありません。私の会社は現在、iPadがモバイルデバイスとして特別に扱われておらず、タッチエンドイベントがまだ必要なプロジェクトに取り組んでいます。しかしtouchendは通常のデスクトップバージョンでは動作しません。したがって、@ mottieのソリューションは、そのシナリオでは完全に問題ありません。
ピート


3

まあ...これらはすべて非常に複雑です。

あなたがmodernizrを持っているなら、それは非常に簡単です。

ev = Modernizr.touch ? 'touchstart' : 'click';

$('#menu').on(ev, '[href="#open-menu"]', function(){
  //winning
});

2
それが何をするか説明できますか?デバイスがタッチをサポートしているかどうかを確認し、サポートしていない場合はクリックを使用すると思います。キャッチはある(あるいは少なくともだった私は質問を書いたとき、)一部のデバイスは両方をサポートしていることでした。トリガーはタッチまたはクリックのどちらからでも発生する可能性があるため、これらのデバイスでは両方のイベントを処理する必要があります。
DA。

2
もう少し説明をお勧めします。
アーロンホール

2

より良いメンテナンスのための別の実装。ただし、この手法はevent.stopPropagation()も実行します。クリックは、100ミリ秒間クリックされた他の要素では捕捉されません。

var clickObject = {
    flag: false,
    isAlreadyClicked: function () {
        var wasClicked = clickObject.flag;
        clickObject.flag = true;
        setTimeout(function () { clickObject.flag = false; }, 100);
        return wasClicked;
    }
};

$("#myButton").bind("click touchstart", function (event) {
   if (!clickObject.isAlreadyClicked()) {
      ...
   }
}

2

文書化の目的で、デスクトップでの最速/最も応答性の高いクリック/モバイルソリューションでのタップのために私が考えたことは次のとおりです。

私はjQueryのon関数を、ブラウザーがタッチイベントをサポートするたびにすべてのクリックイベントをtouchstartに置き換える変更された関数に置き換えました。

$.fn.extend({ _on: (function(){ return $.fn.on; })() });
$.fn.extend({
    on: (function(){
        var isTouchSupported = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
        return function( types, selector, data, fn, one ) {
            if (typeof types == 'string' && isTouchSupported && !(types.match(/touch/gi))) types = types.replace(/click/gi, 'touchstart');
            return this._on( types, selector, data, fn);
        };
    }()),
});

次のように、以前とまったく同じように使用します。

$('#my-button').on('click', function(){ /* ... */ });

ただし、利用可能な場合はタッチスタートを使用し、利用できない場合はクリックします。遅延は必要ありません:D


1
これの欠点は、両方の操作に対応していることを確認する必要がある、タッチとキーボードの両方をサポートするデバイスです。
DA。

良い観察@DA。タッチイベントと組み合わせて使用​​しない場合にのみ、クリックイベントを置き換えるチェックを追加しました。Stilがすべてのプロジェクトの解決策となるわけではありませんが、多くのプロジェクトに適していると思います。
Gerson Goulart 2013

2

ontouchstartトリガーされたかどうかを記憶するというアイデアを思いついたところです。この場合、それをサポートするデバイスを使用しており、onclickイベントを無視します。ontouchstart常にトリガーされる はずなのでonclick、私はこれを使用しています:

<script> touchAvailable = false; </script>
<button ontouchstart="touchAvailable=true; myFunction();" onclick="if(!touchAvailable) myFunction();">Button</button>


1
ユーザーが同じページにアクセスしているときにタッチとマウスを使用する可能性があるため、このスニペットの問題は、イベントごとではなく一度、touchAvailableフラグを登録することです。stackoverflow.com/a/26145343/328272のjQueryプラグインはコードと同じですが、イベントによってタッチまたはマウスのどちらでトリガーされたかをマウスイベントに通知できます。だけでなく。クリック時だけでなく、マウス入力後数秒(または数分)でトリガーされる可能性のあるマウスリーブ(マウスジェスチャーでマウスオーバーしたとき、またはタッチを使用してクリックしたときに展開するフライアウトメニューに最適)。
lmeurs 2014

2

あなたはこのように試すことができます:

var clickEvent = (('ontouchstart' in document.documentElement)?'touchstart':'click');
$("#mylink").on(clickEvent, myClickHandler);

タッチとマウスをサポートするデバイスについてはどう
ですか

2

私の場合、これは完全に機能しました:

jQuery(document).on('mouseup keydown touchend', function (event) {
var eventType = event.type;
if (eventType == 'touchend') {
    jQuery(this).off('mouseup');
}
});

主な問題は、マウスでクリックして試したところ、タッチデバイスでクリックとタッチエンドが同時にトリガーされ、クリックオフを使用すると、モバイルデバイスで一部の機能がまったく動作しなかったということでした。クリックの問題は、touchendを含むイベントの残りの部分を起動するグローバルイベントであることです。


1

これは私にとってはうまくいきました、モバイルは両方を聞くので、タッチイベントである1つを防ぎます。デスクトップはマウスだけを聞きます。

 $btnUp.bind('touchstart mousedown',function(e){
     e.preventDefault();

     if (e.type === 'touchstart') {
         return;
     }

     var val = _step( _options.arrowStep );
               _evt('Button', [val, true]);
  });

1

私にとってはMottieによって与えられた最良の答えであるので、私は彼のコードをより再利用可能なものにしようとしているだけなので、これが私の貢献です。

bindBtn ("#loginbutton",loginAction);

function bindBtn(element,action){

var flag = false;
$(element).bind('touchstart click', function(e) {
    e.preventDefault();
    if (!flag) {
        flag = true;
        setTimeout(function() {
            flag = false;
        }, 100);
        // do something
        action();
    }
    return false;
});

0

私はAndroid / iPadウェブアプリにも取り組んでおり、「touchmove」を使用するだけで「コンポーネントを移動」できる場合は(touchstartは不要)と思われます。touchstartを無効にすることで、.click();を使用できます。jQueryから。touchstartによってオーバーロードされていないため、実際に機能しています。

最後に、.live( "touchstart"、function(e){e.stopPropagation();});をバインドできます。伝達を停止するようにtouchstartイベントに要求し、トリガーされるためにクリック()するために居間。

それは私のために働いた。


どのように無効にしtouchstartますか?
punkrockbuddyholly 2012

私はあなたが次のようなことを「できる」と信じています:jQuery( "#my_element")。on( 'touchstart'、function(e){e.preventDefault()});
nembleton 2012

0

この問題を解決しようとするときに考慮すべき多くの事柄があります。ほとんどのソリューションは、スクロールを中断するか、ゴーストクリックイベントを適切に処理しません。

完全なソリューションについては、 https://developers.google.com/mobile/articles/fast_buttonsをください

注意:ゴーストクリックイベントを要素ごとに処理することはできません。遅延クリックは画面の場所によって発生するため、タッチイベントが何らかの方法でページを変更した場合、クリックイベントは新しいバージョンのページに送信されます。


0

イベントに割り当てる'touchstart mousedown''touchend mouseup'、を使用することによる望ましくない副作用を回避することが効果的clickです。


0

クリックは常にタッチイベントに続くという事実を利用して、タイムアウトやグローバルフラグを使用せずに「ゴーストクリック」を取り除くために、次のことを行いました。

$('#buttonId').on('touchstart click', function(event){
    if ($(this).data("already")) {
        $(this).data("already", false);
        return false;
    } else if (event.type == "touchstart") {
        $(this).data("already", true);
    }
    //your code here
});

基本的ontouchstartに、要素でイベントが発生するたびに、フラグがセットになり、クリックが発生したときに削除(および無視)されます。


0

jQuery Event APIを使用しないのはなぜですか?

http://learn.jquery.com/events/event-extensions/

私は成功したこの単純なイベントを使用しました。クリーンで名前空間があり、十分に改善できる柔軟性があります。

var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);
var eventType = isMobile ? "touchstart" : "click";

jQuery.event.special.touchclick = {
  bindType: eventType,
  delegateType: eventType
};

1
ユーザーエージェントスニッフィングよりも機能検出を使用することをお勧めします。
jinglesthula 14

キャッチは、タッチとクリックの両方をサポートするデバイスです。
DA。

0

jQueryを使用している場合は、次の方法でうまくいきました。

var callback; // Initialize this to the function which needs to be called

$(target).on("click touchstart", selector, (function (func){
    var timer = 0;
    return function(e){
        if ($.now() - timer < 500) return false;
        timer = $.now();
        func(e);
    }
})(callback));

他の解決策も良いですが、ループで複数のイベントをバインドしていて、適切なクロージャーを作成するために自己呼び出し関数が必要でした。また、次のクリック/タッチスタートで起動できるようにしたいので、バインディングを無効にしたくありませんでした。

同様の状況で誰かを助けるかもしれません!


0

単純な機能の場合、タッチまたはクリックを認識するだけで、次のコードを使用します。

var element = $("#element");

element.click(function(e)
{
  if(e.target.ontouchstart !== undefined)
  {
    console.log( "touch" );
    return;
  }
  console.log( "no touch" );
});

これは、touchstartイベントが定義されている場合は「touch」を返し、定義されていない場合は「no touch」を返します。私が言ったように、これはそれだけのクリック/タップイベントのためのシンプルなアプローチです。


0

私はこれを試していますが、これまでのところ動作します(ただし、私はAndroid / Phonegapでのみ使用しているため、注意が必要です)

  function filterEvent( ob, ev ) {
      if (ev.type == "touchstart") {
          ob.off('click').on('click', function(e){ e.preventDefault(); });
      }
  }
  $('#keypad').on('touchstart click', '.number, .dot', function(event) {
      filterEvent( $('#keypad'), event );
      console.log( event.type );  // debugging only
           ... finish handling touch events...
  }

すべてのタッチでハンドラーを再バインドしているのが気に入らないが、タッチと見なされるすべてのことが頻繁に発生するわけではない(コンピューター時間では!)

私は '#keypad'のようなハンドラーのTONを持っているので、コードを多くせずに問題に対処できる単純な関数があるので、この方法を採用しました。



0

編集:(このスレッドの回答に基づく)私の以前の回答は、私のために行く方法ではありませんでした。マウスのEnterキーまたはタッチクリックで展開し、マウスから離れるか別のタッチクリックで折りたたむサブメニューが必要でした。マウスイベントは通常、タッチイベントの後に発生するため、タッチスクリーンとマウス入力の両方を同時にサポートするイベントリスナーを作成するのは、少し難しい作業でした。

jQueryプラグイン:タッチまたはマウス

結局、イベントがタッチスクリーンとマウスのどちらで呼び出されたかを(タッチサポートのテストなしで)検出できる「Touch Or Mouse」(897バイトに縮小)というjQueryプラグインを作成しました。これは、タッチスクリーンとマウスの両方のサポートが可能になり、同時に、完全に自分のイベントを分離します。

このようにして、OPは、タッチクリックを使用しtouchstartたりtouchend、タッチクリックにすばやく応答したり、マウスによってのみclick呼び出されるクリックを実行したりできます。

デモンストレーション

最初に、IEを作成する必要があります。body要素はタッチイベントを追跡します。

$(document.body).touchOrMouse('init');

マウスイベントは、デフォルトの方法で要素にバインドされており、呼び出す$body.touchOrMouse('get', e)ことにより、イベントがタッチスクリーンとマウスのどちらで呼び出されたかを確認できます。

$('.link').click(function(e) {
  var touchOrMouse = $(document.body).touchOrMouse('get', e);

  if (touchOrMouse === 'touch') {
    // Handle touch click.
  }
  else if (touchOrMouse === 'mouse') {
    // Handle mouse click.
  }
}

http://jsfiddle.net/lmeurs/uo4069nhで作業中のプラグインを参照してください

説明

  1. このプラグインは、IEで呼び出す必要があります。追跡するbody要素touchstarttouchendイベント。これにより、touchendイベントをトリガー要素(つまり、リンクまたはボタン)で発生させる必要がなくなります。これら2つのタッチイベントの間で、このプラグインは、マウスイベントがタッチによって呼び出されると見なします。
  2. マウスイベントはの後にのみtouchend発生します。マウスイベントがghostEventDelay(オプション、デフォルトでは1000ms)の後に発生するとtouchend、このプラグインはマウスイベントがタッチによって呼び出されたと見なします。
  3. タッチスクリーンを使用して要素をクリックすると、要素は:active状態を取得します。mouseleave要素、すなわちによってこの状態を失った後にイベントにのみ起動されます。別の要素をクリックします。これはmouseenterイベントが発生してから数秒(または数分!)になる可能性があるため、このプラグインは要素の最後のmouseenterイベントを追跡します。最後のmouseenterイベントがタッチによって呼び出された場合、次のmouseleaveイベントもタッチによって呼び出されたと見なされます。

0

簡単な方法は次のとおりです。

// A very simple fast click implementation
$thing.on('click touchstart', function(e) {
  if (!$(document).data('trigger')) $(document).data('trigger', e.type);
  if (e.type===$(document).data('trigger')) {
    // Do your stuff here
  }
});

基本的に、トリガーされる最初のイベントタイプを、ルートドキュメントに添付されているjQueryのデータオブジェクトの「トリガー」プロパティに保存し、イベントタイプが「トリガー」の値と等しい場合にのみ実行します。タッチデバイスでは、イベントチェーンは「touchstart」の後に「click」が続く可能性があります。ただし、「クリック」が「トリガー」に保存された初期イベントタイプ(「タッチスタート」)と一致しないため、「クリック」ハンドラは実行されません。

安全であると私は思いますが、「トリガー」イベントタイプは1回に1回しか保存されないため、スマートフォンがタッチデバイスからマウスデバイスに自発的に変化しないか、タップが登録されません。ページの読み込みと「クリック」が「touchstart」と一致することはありません。

これはあなたがいじり回すことができるコードペンです(タッチデバイスのボタンをタップしてみてください-クリック遅延はないはずです):http : //codepen.io/thdoan/pen/xVVrOZ

また、セレクター文字列を渡すことでjQueryの子孫フィルタリングもサポートする単純なjQueryプラグインとしてこれを実装しました。

// A very simple fast click plugin
// Syntax: .fastClick([selector,] handler)
$.fn.fastClick = function(arg1, arg2) {
  var selector, handler;
  switch (typeof arg1) {
    case 'function':
      selector = null;
      handler = arg1;
      break;
    case 'string':
      selector = arg1;
      if (typeof arg2==='function') handler = arg2;
      else return;
      break;
    default:
      return;
  }
  this.on('click touchstart', selector, function(e) {
    if (!$(document).data('trigger')) $(document).data('trigger', e.type);
    if (e.type===$(document).data('trigger')) handler.apply(this, arguments);
  });
};

Codepen:http ://codepen.io/thdoan/pen/GZrBdo/


単に変数を使用する代わりに、ドキュメントのデータプロパティを使用したのはなぜですか?
Raphael Schweikert

@RaphaelSchweikertたぶん癖がありません。正しい方法や間違った方法は$.data()ありませんが、複数の関数からアクセスできるが、グローバルスコープには属さないデータを格納するために使用するのが好きです。プラスは、それを要素に格納しているため、自然により多くのコンテキストが提供されることです。
thdoan 2016

0

私が見つけた最良の方法は、タッチイベントを記述し、そのイベントで通常のクリックイベントをプログラム的に呼び出すことです。このようにして、すべての通常のクリックイベントを取得し、すべてのタッチイベントに対して1つのイベントハンドラーを追加する必要があります。タッチ可能にしたいすべてのノードについて、 "touchable"クラスをノードに追加して、タッチハンドラーを呼び出します。Jqueryを使用すると、誤検知ではなく実際のタッチイベントを確実にするためのロジックを使用して、そのように機能します。

$("body").on("touchstart", ".touchable", function() { //make touchable  items fire like a click event
var d1 = new Date();
var n1 = d1.getTime();
setTimeout(function() {
    $(".touchable").on("touchend", function(event) {
        var d2 = new Date();
        var n2 = d2.getTime();
        if (n2 - n1 <= 300) {
            $(event.target).trigger("click"); //dont do the action here just call real click handler
        }
    });
}, 50)}).on("click", "#myelement", function() {
//all the behavior i originally wanted
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.