Bagaimana cara mengikat 'touchstart' dan 'klik' acara tetapi tidak menanggapi keduanya?

198

Saya sedang mengerjakan situs web seluler yang harus bekerja di berbagai perangkat. Yang membuat saya sakit kepala saat ini adalah BlackBerry.

Kita perlu mendukung klik keyboard dan juga acara sentuh.

Idealnya saya hanya menggunakan:

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

tetapi masalah yang kita hadapi adalah bahwa beberapa perangkat blackberry ini memiliki penundaan yang sangat mengganggu dari saat disentuh hingga memicu klik.

Obatnya adalah dengan menggunakan touchstart:

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

Tetapi bagaimana saya bisa mengikat kedua acara, tetapi hanya menembak satu? Saya masih membutuhkan acara klik untuk perangkat keyboard, tetapi tentu saja, tidak ingin acara klik diaktifkan jika saya menggunakan perangkat sentuh.

Pertanyaan bonus: Apakah ada cara untuk melakukan ini dan juga mengakomodasi browser yang bahkan tidak memiliki acara touchstart? Dalam meneliti ini, sepertinya BlackBerry OS5 tidak mendukung touchstart sehingga juga perlu mengandalkan acara klik untuk browser itu.

TAMBAHAN:

Mungkin pertanyaan yang lebih komprehensif adalah:

Dengan jQuery, apakah mungkin / direkomendasikan untuk menangani interaksi sentuhan dan interaksi mouse dengan binding yang sama?

Idealnya, jawabannya adalah ya. Jika tidak, saya punya beberapa opsi:

1) Kami menggunakan WURFL untuk mendapatkan info perangkat sehingga dapat membuat matriks perangkat kami sendiri. Bergantung pada perangkat, kami akan menggunakan touchstart ATAU klik.

2) Mendeteksi dukungan sentuh di browser melalui JS (Saya perlu melakukan penelitian lebih lanjut tentang itu, tetapi sepertinya itu bisa dilakukan).

Namun, itu masih menyisakan satu masalah: bagaimana dengan perangkat yang mendukung KEDUA. Beberapa ponsel yang kami dukung (yaitu Nokias dan BlackBerries) memiliki layar sentuh dan keyboard. Jadi hal itu membuat saya kembali ke pertanyaan semula ... adakah cara untuk memungkinkan keduanya sekaligus?

DA.
sumber
2
Anda lebih baik mengikat untuk menyentuh dan menyentuh dan menulis logika klik Anda sendiri di samping logika sentuhan Anda. Panggilan balik klik bawaan karena tidak ada pengetahuan tentang sentuhan.
Justin808
Saya tidak yakin saya mengikuti, Justin. Bukankah saya masih memiliki touchstart dan klik acara terikat padanya?
DA.
@ DA - tidak, Anda tidak akan terikat dengan panggilan balik .click () sama sekali. Saya akan mencoba menulis jawaban dalam beberapa kode sudo. Saya tidak punya perangkat sentuh yang berguna untuk menulis kode sungguhan :)
Justin808
Ah, tetapi untuk mengklarifikasi, saya masih perlu acara klik, karena akan ada orang yang mengakses situs ini dengan perangkat non-sentuh.
DA.
2
Menggunakan .bind('touchstart mouseup')akan menyelesaikannya (berdasarkan salah satu komentar di bawah)
oriadam

Jawaban:

135

Pembaruan : Lihat proyek jQuery Pointer Events Polyfill yang memungkinkan Anda untuk mengikat "penunjuk" acara daripada memilih antara mouse & touch.


Ikat keduanya, tetapi buat bendera sehingga fungsinya hanya menyala sekali per 100 ms atau lebih.

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

  return false
});
Mottie
sumber
7
hmm ... rasanya dirusak, tapi itu bisa bekerja Tangkapannya adalah bahwa pada beberapa perangkat ini, ini kelambatan yang nyata ... mungkin hampir satu detik ... yang akan mengganggu bagi orang lain pada perangkat yang lebih cepat.
DA.
15
Alih-alih menggunakan clickmengubahnya ke mousedown... mungkin penundaan yang lama adalah perbedaan antara mousedowndan mouseupbagaimana cara clickditentukan.
Mottie
7
Ini adalah solusi yang saya gunakan. Terima kasih! Apa yang saya lakukan adalah saya menandai item touchenddengan menerapkan kelas touched. Kebakaran ini sebelum acara klik disebut. Saya kemudian menambahkan acara klik yang pertama memeriksa keberadaan kelas itu. Jika ada, kami menganggap acara sentuh diaktifkan dan kami tidak melakukan apa pun dengan klik selain menghapus nama kelas untuk 'mengatur ulang' untuk interaksi berikutnya. Jika kelas tidak ada di sana, maka kami menganggap mereka telah menggunakan keyboard untuk mengklik item, dan memicu fungsi dari sana.
DA.
7
Anda harus menyadari bahwa sebagian besar peramban ponsel memiliki keterlambatan 300 ms pada acara klik, jadi Anda harus meningkatkan penundaan menjadi setidaknya 300, Lihat artikel ini tentang masalah keterlambatan 300 ms . Ini pada dasarnya untuk mengaktifkan fungsionalitas "klik dua kali untuk memperbesar" yang merupakan fitur yang sangat penting di awal masa iPhone, ketika sebagian besar situs web dirancang untuk dilihat pada layar desktop yang besar.
awe
12
Pertanyaan ini telah dilihat hampir 100 ribu kali pada saat ini. Ini sepertinya kasus / masalah penggunaan yang sangat umum. Namun, jawaban ini dan yang lain tentang ini dan pertanyaan serupa semuanya tampak berantakan. Solusi google, walaupun lebih teliti daripada kebanyakan, sepertinya hanya peretasan yang lebih kuat. Untuk sesuatu yang sederhana seperti penangan klik, sepertinya solusinya harus sederhana. Tidak ada yang menemukan solusi non-hack untuk masalah ini?
jinglesthula
73

Ini adalah perbaikan yang saya "buat" dan mengeluarkan GhostClick dan mengimplementasikan FastClick. Coba sendiri dan beri tahu kami jika itu berhasil untuk Anda.

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

        // Do your magic here

});
Rafael Fragoso
sumber
2
helgatheviking: jsbin.com/ijizat/25 Dalam JavaScript ada fungsi yang disebut TouchClick yang menggabungkan di atas.
Matt Parkins
5
Saya SANGAT suka metode ini dari semua jawaban untuk pertanyaan ini karena ini a) tidak menguji kemampuan perangkat dan b) tidak menggunakan setTimeout. Dalam pengalaman saya, solusi untuk masalah seperti ini yang menggunakan setTimeout dapat berfungsi untuk sebagian besar kasus tetapi waktu kejadiannya cukup sewenang-wenang dan khusus untuk perangkat.
nya tempat
7
Ini tidak akan berhasil karena dengan melewati 'acara' dalam fungsi anonim itu menjadi objek lokal dalam fungsi itu, sehingga event.handledakan sama undefinedsetiap kali acara dipicu. Inilah solusinya: atur bendera 'ditangani' di elemen target itu sendiri dengan menggunakan jQuery.data().
thdoan
3
Anda memiliki event.stopPropagation();dan event.preventDefault();dari pemahaman saya (dan pengujian) acara hanya dapat dipecat sekali dengan ini. jadi mengapa memeriksa if(event.handled !== true)? Bagi saya itu tidak perlu atau apakah saya melewatkan sesuatu?
nbar
2
Tidak event.handledharus diperiksa nilainya true? Sejauh yang saya tahu itu tidak pernah false. Ini dimulai sebagai undefined, dan kemudian Anda ingin tahu apakah sudah diatur true.
ACJ
49

Anda dapat mencoba sesuatu seperti ini:

var clickEventType=((document.ontouchstart!==null)?'click':'touchstart');
$("#mylink").bind(clickEventType, myClickHandler);
swooter
sumber
5
Saya pikir masalah dengan itu adalah pengujian kemampuan perangkat daripada apa yang dilakukan pengguna, bukan? Tantangannya adalah kita perlu mendukung perangkat sentuh yang juga memiliki keyboard (sehingga mereka dapat menggunakan keduanya)
DA.
8
Ini bukan ide yang baik - akan merusak acara untuk pengguna dengan layar sentuh dan mouse saat menggunakan mouse (laptop dengan layar sentuh menjadi sangat umum).
Kristian J.
1
Artikel yang luar biasa terkait dengan ini: hacks.mozilla.org/2013/04/...
Luke Melia
Windows 8 akan selalu memasang acara 'touchstart' jika ini digunakan karena 'ontouchstart' akan mengembalikan 'true' untuk OS ini. Jadi, mungkin bukan jawaban terbaik kecuali kode Anda hanya akan berjalan pada perangkat layar sentuh yang sebenarnya, tetapi jika itu masalahnya, Anda tidak perlu memeriksa sama sekali.
Neil Monroe
Pada laptop dengan layar sentuh, pengguna tidak akan dapat mengklik apa pun menggunakan kode ini dalam chrome (setidaknya chrome 46). IE 11 tampaknya berfungsi.
David Sherret
42

Biasanya ini berfungsi juga:

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

});
Jonathan
sumber
8
@ Jonathan salah, jika Anda menggunakan versi jQuery yang lebih baru. Live sudah tidak digunakan lagi dalam versi 1.7.
Mike Barwick
Saya juga mencoba (dan saya membacanya di tempat lain - bukan ide saya) dengan e.stopPropagation (); e.preventDefault (); dan itu bekerja (untuk saya) hampir tetapi saya menemukan kemudian bahwa sebenarnya itu berfungsi seperti yang diprediksi 20 kali tetapi 1 kali tidak, jadi itu bukan antipeluru. Lihat di sini: stackoverflow.com/questions/25671053/... Hargai komentar Anda tentang masalah itu!
Garavani
@MikeBarwick Bisakah Anda menjelaskan komentar Anda atau memberikan tautan yang menjelaskannya? Terima kasih sebelumnya.
Billal Begueradj
22

Hanya menambahkan return false;di akhir on("click touchstart")fungsi acara dapat menyelesaikan masalah ini.

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

Dari dokumentasi jQuery di .on ()

Kembali falsedari pengendali acara akan secara otomatis menelepon event.stopPropagation()dan event.preventDefault(). Sebuah falsenilai juga dapat ditularkan untuk handler sebagai singkatan untuk function(){ return false; }.

Roy
sumber
2
berfungsi dengan baik, hanya sekali kebakaran pada perangkat dengan keduanya - ini sepertinya solusi paling tidak rapi untuk saya
Adam Cooper
Bekerja paling baik untuk saya dan benar-benar masuk akal mengapa.
Amir5000
Adakah kerugian untuk ini? Mengapa solusi sederhana seperti itu tidak banyak diketahui?
ESR
10

Saya harus melakukan hal serupa. Ini adalah versi sederhana dari apa yang berhasil untuk saya. Jika acara sentuh terdeteksi, hapus ikatan klik.

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

  //your code here
});

Dalam kasus saya, peristiwa klik terikat ke suatu <a>elemen, jadi saya harus menghapus ikatan klik dan memutar balik peristiwa klik yang mencegah tindakan default untuk <a>elemen tersebut.

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

  //your code here
});
Tim
sumber
Saya berharap ini berfungsi sebagaimana mestinya, tetapi tidak. $ (ini) tidak menunjukkan apa yang Anda pikirkan.
Dave Lowerre
8

Saya berhasil dengan cara berikut.

Peasy mudah ...

$(this).on('touchstart click', function(e){
  e.preventDefault();
  //do your stuff here
});
Hasanavi
sumber
4
bukankah itu akan menyala dua kali pada perangkat yang mendaftarkan klik dan sentuh?
DA.
8
Maaf, saya membuat Anda tahu. Ya, Anda benar sentuhan akan menghasilkan acara touchstart dan klik acara juga. Ini disebut klik hantu. Google telah menerapkan solusi untuk itu. Mungkin tidak lurus ke depan tetapi bekerja dengan sempurna. Ini tautannya. code.google.com/mobile/articles/fast_buttons.html#ghost
Hasanavi
2
mungkin sepele tapi kau hilang eparameter difunction()
ProblemsOfSumit
@ Hanasanavi ini adalah perbaikan yang hebat namun saya menemukan hasil yang lebih baik menggunakan .on
Neil
1
Terima kasih @Neil. Ya menggunakan .on adalah ide yang lebih baik karena mungkin akan dihapus di versi mendatang. Saya telah mengubah contoh saya dari bind ke on.
Hasanavi
5

Saya percaya praktik terbaik sekarang adalah menggunakan:

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

touchend

Acara touchend dipecat ketika titik sentuh dihapus dari permukaan sentuh.

Acara touchend tidak akan memicu acara mouse apa pun.


mouseup

Acara mouseup dikirim ke elemen ketika pointer mouse di atas elemen, dan tombol mouse dilepaskan. Setiap elemen HTML dapat menerima acara ini.

Acara mouseup tidak akan memicu acara sentuh apa pun.

CONTOH

$('#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>


EDIT (2017)

Mulai 2017, browser dimulai dengan Chrome dan membuat langkah menuju pembuatan acara klik .on("click") lebih kompatibel untuk mouse dan sentuhan dengan menghilangkan penundaan yang dihasilkan oleh acara ketuk pada permintaan klik.

Ini mengarah pada kesimpulan bahwa kembali menggunakan hanya peristiwa klik akan menjadi solusi paling sederhana untuk maju.

Saya belum melakukan pengujian lintas browser untuk melihat apakah ini praktis.

DreamTeK
sumber
Ini tampak menjanjikan bagi saya, jadi saya bermain-main dengannya, tetapi pada akhirnya saya menemukan mouseuphasil yang tidak terduga, terutama ketika menggunakan trackpad daripada mouse tradisional.
skybondsor
4

Secara umum Anda tidak ingin mencampur api sentuh dan non-sentuh (klik) default. Setelah Anda pindah ke dunia sentuhan, lebih mudah untuk berurusan hanya dengan fungsi terkait sentuhan. Di bawah ini adalah beberapa kode pseudo yang akan melakukan apa yang Anda inginkan.

Jika Anda terhubung dalam acara touchmove dan melacak lokasi, Anda dapat menambahkan lebih banyak item di fungsi doTouchLogic untuk mendeteksi gerakan dan yang lainnya.

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
     }
}
Justin808
sumber
Saya kira itulah inti dari pertanyaan: apakah masuk akal untuk mencoba dan mendukung kedua model dengan satu basis kode. Saya akan memperbarui pertanyaan saya dengan beberapa skenario lagi.
DA.
1
"Secara umum Anda tidak ingin mencampur sentuhan default dan non-touch" setelah melalui ini, saya setuju. Masalahnya adalah mereka terus membuat perangkat sentuh dengan keyboard, yang merupakan sakit kepala bagi kami para pengembang.
DA.
Saya setuju bahwa akan jauh lebih mudah untuk dilakukan di awal sentuhan akhir keputusan atau tidak ada sentuhan. Dunia yang begitu mudah! Tapi apa ini tentang klik dan sentuh perangkat terkutuk masuk akal? Apakah layak untuk semua sakit kepala itu karena mereka? Apakah ini masa depan yang saya tanyakan pada diri saya sendiri?
Garavani
Saya tidak suka gagasan memiliki banyak definisi fungsi. Perusahaan saya saat ini sedang mengerjakan proyek di mana iPad tidak ditangani secara khusus sebagai perangkat seluler dan Anda masih memerlukan acara touchend. Tetapi touchend tidak berfungsi pada versi desktop normal. Jadi solusi @mottie sangat baik untuk skenario itu.
Pete
3

Baiklah ... Semua ini sangat rumit.

Jika Anda memiliki modernizr, itu adalah no-brainer.

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

$('#menu').on(ev, '[href="#open-menu"]', function(){
  //winning
});
sumbing
sumber
2
Bisakah Anda menjelaskan apa fungsinya? Saya percaya ini memeriksa untuk melihat apakah perangkat mendukung sentuhan dan jika tidak, menggunakan klik. Tangkapannya adalah (atau paling tidak , ketika saya menulis pertanyaan) adalah bahwa beberapa perangkat mendukung keduanya. Dan pada perangkat itu, saya masih perlu menangani kedua acara tersebut, karena pemicunya dapat berasal dari sentuhan atau klik.
DA.
2
Saya merekomendasikan sedikit penjelasan.
Aaron Hall
2

Implementasi lain untuk pemeliharaan yang lebih baik. Namun, teknik ini juga akan melakukan event.stopPropagation (). Klik tidak tertangkap pada elemen lain yang diklik selama 100 ms.

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()) {
      ...
   }
}
hammer mathieu
sumber
2

Hanya untuk keperluan dokumentasi, inilah yang telah saya lakukan untuk klik tercepat / paling responsif pada desktop / ketuk pada solusi seluler yang dapat saya pikirkan:

Saya mengganti onfungsi jQuery dengan yang dimodifikasi yang, setiap kali browser mendukung acara sentuh, mengganti semua acara klik saya dengan 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);
        };
    }()),
});

Penggunaan daripada akan sama persis seperti sebelumnya, seperti:

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

Tapi itu akan menggunakan touchstart saat tersedia, klik bila tidak. Tidak ada penundaan dalam bentuk apa pun: D

Gerson Goulart
sumber
1
Tangkapan dengan ini akan menjadi perangkat yang mendukung KEDUA sentuh DAN keyboard di mana Anda perlu memastikan Anda mengakomodasi kedua interaksi.
DA.
Pengamatan bagus @DA. Saya menambahkan tanda centang untuk hanya mengganti acara klik jika Anda tidak menggunakan acara sentuh apa pun yang dikombinasikan dengannya. Stil tidak akan menjadi solusi untuk setiap proyek, tapi saya yakin akan cocok untuk banyak orang.
Gerson Goulart
2

Saya baru saja datang dengan ide untuk menghafal jika ontouchstartpernah dipicu. Dalam hal ini kami menggunakan perangkat yang mendukungnya dan ingin mengabaikan onclickacara tersebut. Karena ontouchstartharus selalu dipicu sebelumnya onclick , saya menggunakan ini:

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

jakob.j
sumber
1
Karena pengguna mungkin menggunakan sentuhan dan mouse selama kunjungan halaman yang sama, masalah dengan snippet ini adalah ia mendaftarkan flag touchAvailable satu kali alih-alih per peristiwa. Plugin jQuery dari stackoverflow.com/a/26145343/328272 melakukan hal yang sama dengan kode Anda, tetapi dapat mengetahui untuk acara mouse apakah dipicu oleh sentuhan atau mouse berdasarkan acara. Tidak hanya yaitu. pada klik, tetapi juga pada mouseleave yang mungkin dipicu detik (atau menit) setelah mouseenter (ideal untuk menu flyout yang seharusnya diperluas pada mouseover dengan gerakan mouse atau klik saat menggunakan sentuhan).
Istirahat
2

Anda dapat mencoba seperti ini:

var clickEvent = (('ontouchstart' in document.documentElement)?'touchstart':'click');
$("#mylink").on(clickEvent, myClickHandler);
Sky Yip
sumber
bagaimana dengan perangkat yang mendukung sentuhan dan mouse
Walle Cyril
2

Dalam kasus saya ini berfungsi dengan baik:

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

Masalah utama adalah ketika bukannya mouseup saya coba klik, pada perangkat sentuh memicu klik dan touchend pada saat yang sama, jika saya menggunakan klik, beberapa fungsi tidak berfungsi sama sekali pada perangkat seluler. Masalah dengan klik adalah bahwa itu adalah acara global yang memecat sisa acara termasuk touchend.

Pepita Ronderos
sumber
1

Ini bekerja untuk saya, ponsel mendengarkan keduanya, jadi cegah salah satunya, yang merupakan acara sentuh. desktop hanya mendengarkan mouse.

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

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

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

Bagi saya jawaban terbaik yang diberikan oleh Mottie, saya hanya mencoba untuk membuat kode-nya lebih dapat digunakan kembali, jadi inilah kontribusi saya:

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;
});
Arco Voltaico
sumber
0

Saya juga bekerja pada aplikasi web Android / iPad, dan tampaknya jika hanya menggunakan "touchmove" sudah cukup untuk "memindahkan komponen" (tidak perlu touchstart). Dengan menonaktifkan touchstart, Anda dapat menggunakan .click (); dari jQuery. Ini sebenarnya berfungsi karena belum kelebihan beban oleh touchstart.

Akhirnya, Anda dapat binb .live ("touchstart", function (e) {e.stopPropagation ();}); untuk meminta acara touchstart berhenti propagasi, ruang tamu mengklik () untuk dipicu.

Ini berhasil untuk saya.

nembleton
sumber
Bagaimana Anda menonaktifkan touchstart?
punkrockbuddyholly
Saya yakin Anda "bisa" melakukan sesuatu seperti: jQuery ("# ​​my_element"). On ('touchstart', function (e) {e.preventDefault ()});
nembleton
0

Ada banyak hal yang perlu dipertimbangkan ketika mencoba menyelesaikan masalah ini. Sebagian besar solusi baik istirahat bergulir atau tidak menangani peristiwa klik hantu dengan benar.

Untuk solusi lengkap, lihat https://developers.google.com/mobile/articles/fast_buttons

NB: Anda tidak bisa menangani acara klik hantu berdasarkan per elemen. Klik yang tertunda dipicu oleh lokasi layar, jadi jika acara sentuh Anda memodifikasi halaman dengan cara tertentu, acara klik akan dikirim ke versi halaman yang baru.

SystemParadox
sumber
0

Mungkin efektif untuk ditugaskan ke acara 'touchstart mousedown'atau 'touchend mouseup'untuk menghindari efek samping yang tidak diinginkan dari penggunaan click.

Steven Lu
sumber
0

Mengambil keuntungan dari fakta bahwa klik akan selalu mengikuti acara sentuhan, di sini adalah apa yang saya lakukan untuk menghilangkan "klik hantu" tanpa harus menggunakan batas waktu atau bendera global.

$('#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
});

Pada dasarnya setiap kali suatu ontouchstartkejadian terjadi pada elemen tersebut, sebuah tanda di set dan kemudian dihapus (dan diabaikan), ketika klik itu datang.

BigMacAttack
sumber
0

Mengapa tidak menggunakan API Acara jQuery?

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

Saya telah menggunakan acara sederhana ini dengan sukses. Ini bersih, namespaceable dan cukup fleksibel untuk diperbaiki.

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
};
mdbiscan
sumber
1
Dianjurkan untuk menggunakan deteksi fitur melalui sniffing agen pengguna.
jinglesthula
Tangkapannya adalah perangkat yang mendukung sentuhan dan klik.
DA.
0

Jika Anda menggunakan jQuery, yang berikut berfungsi dengan baik untuk saya:

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));

Solusi lain juga bagus tapi saya mengikat banyak acara dalam satu lingkaran dan membutuhkan fungsi self calling untuk membuat penutupan yang tepat. Juga, saya tidak ingin menonaktifkan pengikatan karena saya ingin dapat dipanggil pada klik / touchstart berikutnya.

Bisa membantu seseorang dalam situasi yang sama!

Yusuf Bhabhrawala
sumber
0

Untuk fitur sederhana, cukup kenali sentuhan atau klik saya menggunakan kode berikut:

var element = $("#element");

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

Ini akan mengembalikan "sentuhan" jika acara touchstart ditentukan dan "tidak ada sentuhan" jika tidak. Seperti yang saya katakan ini adalah pendekatan sederhana untuk acara klik / ketuk saja.

Rodrigo
sumber
0

Saya mencoba ini dan sejauh ini berhasil (tapi saya hanya di Android / Phonegap jadi peringatan emptor)

  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...
  }

Saya tidak suka fakta bahwa saya mengikat kembali penangan pada setiap sentuhan, tetapi semua hal yang dianggap sentuhan tidak terlalu sering terjadi (dalam waktu komputer!)

Saya memiliki TON penangan seperti '#keypad' sehingga memiliki fungsi sederhana yang memungkinkan saya menangani masalah tanpa terlalu banyak kode adalah alasan saya menggunakan cara ini.

Dave Lowerre
sumber
0

EDIT: Jawaban saya sebelumnya (berdasarkan jawaban di utas ini) bukan cara yang cocok untuk saya. Saya ingin sub-menu untuk memperluas masuk mouse atau menyentuh klik dan untuk runtuh pada cuti mouse atau klik sentuh lainnya. Karena peristiwa mouse biasanya dipecat setelah peristiwa sentuhan, agak sulit untuk menulis pendengar acara yang mendukung input layar sentuh dan mouse pada saat yang sama.

Plugin jQuery: Sentuh Atau Mouse

Saya akhirnya menulis sebuah plugin jQuery yang disebut " Touch Or Mouse " (diperkecil 897 bytes) yang dapat mendeteksi apakah suatu peristiwa dipanggil oleh layar sentuh atau mouse (tanpa pengujian untuk dukungan sentuh!). Ini memungkinkan dukungan layar sentuh dan mouse secara bersamaan dan benar-benar memisahkan acara mereka.

Dengan cara ini OP dapat menggunakan touchstartatau touchenduntuk cepat menanggapi klik sentuhan dan clickuntuk klik dipanggil hanya oleh mouse.

Demonstrasi

Yang pertama harus dibuat yaitu. acara sentuhan elemen trek:

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

Peristiwa mouse kami terikat ke elemen dengan cara default dan dengan memanggil $body.touchOrMouse('get', e)kami dapat mengetahui apakah acara itu dipanggil oleh layar sentuh atau mouse.

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

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

Lihat plugin di tempat kerja di http://jsfiddle.net/lmeurs/uo4069nh .

Penjelasan

  1. Plugin ini perlu dipanggil yaitu. elemen tubuh untuk dilacak touchstartdan touchendacara, dengan cara ini touchendacara tidak harus diaktifkan pada elemen pemicu (mis. tautan atau tombol). Di antara kedua acara sentuh ini, plugin ini menganggap acara mouse apa pun untuk dipanggil oleh sentuhan.
  2. Acara mouse dipecat hanya setelah touchend, ketika acara mouse dipecat di dalam ghostEventDelay(opsi, 1000 ms secara default) setelah touchend, plugin ini menganggap acara mouse untuk dipanggil oleh sentuhan.
  3. Saat mengklik suatu elemen menggunakan layar sentuh, elemen tersebut memperoleh :activestatus. The mouseleaveevent hanya dipecat setelah elemen kehilangan negara ini dengan yaitu. mengklik elemen lain. Karena ini bisa berupa detik (atau menit!) Setelah mouseenteracara dipecat, plugin ini melacak mouseenteracara terakhir elemen : jika mouseenteracara terakhir dipanggil dengan sentuhan, mouseleaveacara berikut ini juga dianggap dipanggil oleh sentuhan.
lmeurs
sumber
0

Berikut cara mudah untuk melakukannya:

// 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
  }
});

Anda pada dasarnya menyimpan tipe peristiwa pertama yang dipicu ke properti 'pemicu' di objek data jQuery yang dilampirkan ke dokumen root, dan hanya mengeksekusi ketika jenis peristiwa sama dengan nilai dalam 'pemicu'. Pada perangkat sentuh, rantai acara kemungkinan akan menjadi 'layar sentuh' diikuti oleh 'klik'; namun, penangan 'klik' tidak akan dieksekusi karena "klik" tidak cocok dengan jenis acara awal yang disimpan dalam 'pemicu' ("touchstart").

Asumsinya, dan saya yakin itu aman, adalah bahwa ponsel cerdas Anda tidak akan secara spontan berubah dari perangkat sentuh ke perangkat mouse atau jika tidak, ketukan tidak akan pernah mendaftar karena jenis acara 'pemicu' hanya disimpan satu kali per memuat halaman dan "klik" tidak akan pernah cocok dengan "touchstart".

Berikut ini adalah codepen yang dapat Anda mainkan (coba ketuk tombol pada perangkat sentuh - seharusnya tidak ada penundaan klik): http://codepen.io/thdoan/pen/xVVrOZ

Saya juga menerapkan ini sebagai plugin jQuery sederhana yang juga mendukung penyaringan keturunan jQuery dengan mengirimkan string pemilih:

// 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/

Terima kasih
sumber
Mengapa Anda menggunakan properti data pada dokumen alih-alih hanya menggunakan variabel?
Raphael Schweikert
@RaphaelSchweikert Mungkin hanya karena kebiasaan. Tidak ada cara yang benar atau salah, tetapi saya suka menggunakan $.data()untuk menyimpan data yang dapat diakses oleh banyak fungsi namun tidak termasuk dalam lingkup global. Nilai tambahnya adalah karena saya menyimpannya dalam sebuah elemen, itu secara alami memberi saya lebih banyak konteks.
thdoan
0

Metode terbaik yang saya temukan adalah menulis acara sentuh dan meminta acara itu memanggil acara klik normal secara terprogram. Dengan cara ini Anda memiliki semua acara klik normal dan kemudian Anda perlu menambahkan hanya satu pengendali acara untuk semua acara sentuh. Untuk setiap simpul yang Anda ingin jadikan terjamah, cukup tambahkan kelas "terjamah" ke dalamnya untuk memanggil penangan sentuh. Dengan Jquery berfungsi seperti itu dengan beberapa logika untuk memastikan itu adalah peristiwa sentuhan nyata dan bukan positif palsu.

$("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
});
mahatrsna
sumber