Bagaimana cara membedakan acara klik tunggal dan acara klik ganda?

116

Saya memiliki satu tombol di li dengan id "my_id". Saya melampirkan dua acara jQuery dengan elemen ini

1.

$("#my_id").click(function() { 
    alert('single click');
});

2.

$("#my_id").dblclick(function() {
    alert('double click');
});

Tapi setiap kali itu memberi saya single click

pengguna426795
sumber
Klik tunggal harus selalu aktif, tidak mungkin untuk mengetahui apakah klik ganda akan terjadi kecuali jika benar-benar terjadi dalam waktu klik ganda yang ditentukan.
Pieter Germishuys
7
Ini mungkin, periksa jawaban saya. Anda harus menunggu beberapa ms setelah klik pertama dan periksa apakah ada klik baru hingga waktu yang ditentukan. Dengan begitu, Anda dapat mengetahui apakah ini hanya dengan satu klik sederhana atau dua kali.
Adrien Schuler

Jawaban:

65

Anda perlu menggunakan waktu tunggu untuk memeriksa apakah ada klik lain setelah klik pertama.

Inilah triknya :

// Author:  Jacek Becela
// Source:  http://gist.github.com/399624
// License: MIT

jQuery.fn.single_double_click = function(single_click_callback, double_click_callback, timeout) {
  return this.each(function(){
    var clicks = 0, self = this;
    jQuery(this).click(function(event){
      clicks++;
      if (clicks == 1) {
        setTimeout(function(){
          if(clicks == 1) {
            single_click_callback.call(self, event);
          } else {
            double_click_callback.call(self, event);
          }
          clicks = 0;
        }, timeout || 300);
      }
    });
  });
}

Pemakaian:

$("button").single_double_click(function () {
  alert("Try double-clicking me!")
}, function () {
  alert("Double click detected, I'm hiding")
  $(this).hide()
})
<button>Click Me!</button>

EDIT:

Seperti yang dinyatakan di bawah, lebih suka menggunakan dblclickacara asli : http://www.quirksmode.org/dom/events/click.html

Atau yang disediakan oleh jQuery: http://api.jquery.com/dblclick/

Adrien Schuler
sumber
14
Ini mungkin tampak bekerja dengan baik secara umum tetapi bukankah jeda waktu yang diperbolehkan antara klik (di mana dua klik diartikan sebagai klik dua kali) berbeda menurut konfigurasi sistem? Mungkin lebih aman untuk mengandalkan dblclickacara
Jon z
1
Ya saya pikir Anda benar, dblclickpasti cara untuk pergi hari ini. jQuery juga menangani acara ini: api.jquery.com/dblclick
Adrien Schuler
14
@AdrienSchuler - Dari dokumen yang Anda tautkan: Tidak disarankan untuk mengikat penangan ke kejadian click dan dblclick untuk elemen yang sama. Pertanyaannya adalah tentang memiliki keduanya .
Álvaro González
Jika event.detailtersedia, ini adalah cara terbaik untuk mendeteksi klik dua kali dari handler klik. Lihat jawaban ini .
Carl G
Solusi bagus Adrien, saya memerlukannya untuk kasus di mana kita memiliki peristiwa klik tunggal dan ganda pada satu objek dan hanya satu yang harus diaktifkan. Oleh karena itu, solusi Anda sangat cocok untuk saya. Saya baru saja meningkatkannya sedikit agar "ini" dapat dikendalikan: playcode.io/492022
LOstBrOkenKeY
79

Perilaku dblclickacara dijelaskan di Quirksmode .

Urutan acara untuk dblclickadalah:

  1. mousedown
  2. mouseup
  3. klik
  4. mousedown
  5. mouseup
  6. klik
  7. dblclick

Satu-satunya pengecualian untuk aturan ini adalah (tentu saja) Internet Explorer dengan urutan kustomnya:

  1. mousedown
  2. mouseup
  3. klik
  4. mouseup
  5. dblclick

Seperti yang Anda lihat, mendengarkan kedua peristiwa secara bersamaan di elemen yang sama akan menghasilkan panggilan tambahan ke clickpenangan Anda .

Ryan
sumber
dblclickbahkan tidak yakin dapat diandalkan ... jika saya klik sekali ... tunggu satu atau dua detik, lalu klik lagi, saya mendapatkan dblclickacara di klik kedua!
Michael
Klik panjang seperti itu berguna misalnya untuk mengganti nama file. Alangkah baiknya jika ada parameter seperti 'longClick' untuk membedakannya.
PeterM
1
Jika event.detailtersedia, ini adalah cara terbaik untuk mendeteksi klik dua kali dari handler klik. Lihat jawaban ini .
Carl G
38

Alih-alih memanfaatkan lebih banyak status ad-hoc dan setTimeout, ternyata ada properti asli bernama detailyang bisa Anda akses dari eventobjek tersebut!

element.onclick = event => {
   if (event.detail === 1) {
     // it was a single click
   } else if (event.detail === 2) {
     // it was a double click
   }
};

Browser modern dan bahkan IE-9 mendukungnya :)

Sumber: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail

kyw
sumber
Jawaban terbaik :)
sk8terboi87 ツ
3
Dalam kasus klik ganda, satu klik (di mana event.detail === 1) masih akan terpicu. Lihat biola saya atau komentar ini di utas ini .
Fabien Snauwaert
Poin bagus @FabienSnauwaert. Saya kira kita tidak bisa mengikat event handler klik tunggal dan ganda pada elemen tertentu; Cara di atas berguna untuk menentukan klik dua kali secara pasti tanpa menggunakan hal-hal seperti timer.
kyw
Anda masih membutuhkan pengatur waktu pada klik pertama itu untuk tidak menembak. Periksa jawaban saya di bawah stackoverflow.com/questions/5497073/…
Hanya catatan aksesibilitas: jika peristiwa klik diaktifkan oleh keyboard (misalnya, saat pengguna tab untuk memfokuskan tombol dan menekan enter), peristiwa dihasilkan dengan properti detail sebagai 0, jadi melakukan sesuatu seperti if(evt.detail !== 1) return;menolak penggandaan yang tidak disengaja klik akan memblokir akses ke tombol itu untuk pengguna tanpa mouse.
gristow
25

Fungsi sederhana. Tidak ada jquery atau framework lain yang dibutuhkan. Teruskan fungsi Anda sebagai parameter

<div onclick="doubleclick(this, function(){alert('single')}, function(){alert('double')})">click me</div>
    <script>
        function doubleclick(el, onsingle, ondouble) {
            if (el.getAttribute("data-dblclick") == null) {
                el.setAttribute("data-dblclick", 1);
                setTimeout(function () {
                    if (el.getAttribute("data-dblclick") == 1) {
                        onsingle();
                    }
                    el.removeAttribute("data-dblclick");
                }, 300);
            } else {
                el.removeAttribute("data-dblclick");
                ondouble();
            }
        }
    </script>
Renzo Ciot
sumber
2
Saya pikir ini harus menjadi jawaban terbaik.Namun, saya harus mengurangi batas waktu menjadi 200 agar berfungsi di Windows IE8, tetapi nilai ini mungkin bergantung pada OS dan pengguna. Dan juga disimpan referensi timer untuk bisa membatalkan eksekusi klik jika double click terdaftar.
xpereta
Terima kasih atas potongan kode ini, ini berfungsi dengan baik pada chrome dan firefox (meskipun chrome tidak memerlukan peretasan ini untuk bekerja dengan dbl dan single).
pemenang
menggunakan el.dataset.dblclickakan menjadi cara yang lebih baik untuk melakukan ini sekarang.
WORMSS
Jika event.detailtersedia, ini adalah cara terbaik untuk mendeteksi klik dua kali dari handler klik. Lihat jawaban ini .
Carl G
12

Saya khawatir perilakunya bergantung pada browser:

Tidak disarankan untuk mengikat penangan ke kejadian click dan dblclick untuk elemen yang sama. Urutan peristiwa yang dipicu bervariasi dari browser ke browser, dengan beberapa menerima dua peristiwa klik sebelum dblclick dan yang lainnya hanya satu. Sensitivitas klik dua kali (waktu maksimum antara klik yang dideteksi sebagai klik dua kali) dapat bervariasi menurut sistem operasi dan browser, dan seringkali dapat dikonfigurasi oleh pengguna.

http://api.jquery.com/dblclick/

Menjalankan kode Anda di Firefox, alert () di click()handler mencegah Anda mengklik untuk kedua kalinya. Jika Anda menghapus peringatan tersebut, Anda mendapatkan kedua peristiwa tersebut.

Álvaro González
sumber
Jika event.detailtersedia, ini adalah cara terbaik untuk mendeteksi klik dua kali dari handler klik. Lihat jawaban ini .
Carl G
11

Nah untuk bisa double click (klik dua kali) kamu harus klik dulu sekali. The click()kebakaran handler pada klik pertama Anda, dan karena peringatan muncul, Anda tidak memiliki kesempatan untuk membuat klik kedua untuk memecat dblclick()handler.

Ubah penangan Anda untuk melakukan sesuatu selain alert()dan Anda akan melihat perilakunya. (mungkin mengubah warna latar belakang elemen):

$("#my_id").click(function() { 
    $(this).css('backgroundColor', 'red')
});

$("#my_id").dblclick(function() {
    $(this).css('backgroundColor', 'green')
});
bradley.ayers
sumber
7

Jawaban ini dibuat usang seiring waktu, periksa solusi @ kyw.

Saya membuat solusi yang terinspirasi oleh inti yang diposting oleh @AdrienSchuler. Gunakan solusi ini hanya jika Anda ingin mengikat satu klik DAN klik dua kali ke elemen. Kalau tidak, saya sarankan menggunakan yang asli clickdandblclick pendengar.

Inilah perbedaannya:

  • Vanillajs, Tanpa ketergantungan
  • Jangan menunggu setTimeout untuk menangani click atau doubleclick handler
  • Saat mengeklik ganda, ini pertama-tama akan mengaktifkan penangan klik, kemudian penangan klik ganda

Javascript:

function makeDoubleClick(doubleClickCallback, singleClickCallback) {
    var clicks = 0, timeout;
    return function() {
        clicks++;
        if (clicks == 1) {
            singleClickCallback && singleClickCallback.apply(this, arguments);
            timeout = setTimeout(function() { clicks = 0; }, 400);
        } else {
            timeout && clearTimeout(timeout);
            doubleClickCallback && doubleClickCallback.apply(this, arguments);
            clicks = 0;
        }
    };
}

Pemakaian:

var singleClick = function(){ console.log('single click') };
var doubleClick = function(){ console.log('double click') };
element.addEventListener('click', makeDoubleClick(doubleClick, singleClick));

Di bawah ini adalah penggunaan di jsfiddle, tombol jQuery adalah perilaku dari jawaban yang diterima.

jsfiddle.dll

A1rPun
sumber
2
Kode di atas dan versi 'Vanilla' dari biola Anda tidak berfungsi ... berikut adalah versi Vanilla tetap: jsfiddle.net/jeum/cpbwx5vr/19
jeum
@jeum Ini masih melakukan trik untuk saya di setiap browser. Apa yang "tidak berhasil" dan apa yang Anda harapkan? Sepertinya versi Anda tidak sesuai dengan keinginan saya.
A1rPun
Pertama Saya telah memodifikasi versi saya (menghapus penutupan ganda), silakan coba yang baru: jsfiddle.net/jeum/cpbwx5vr/20 Masalah dengan biola Anda (versi Vanilla) adalah bahwa klik dua kali memicu penangan tunggal: ia mengambil satu + ganda untukku.
jeum
@jeum Yang satu memberikan kesalahan. Ya, jawaban saya berbeda dari jawaban yang diterima dan jawaban lain di sini dan saya juga menentukan perbedaan ini di baris ini: Tembak satu klik, lalu klik ganda (jangan langsung ke klik ganda)
A1rPun
1
Ya kesalahan lagi, jadi versi ini menanggapi pertanyaan utama: jsfiddle.net/jeum/cpbwx5vr/21 . Sekarang mengenai versi Anda (memang benar saya tidak mengerti), pernahkah Anda memperhatikan bahwa 'jQuery' tidak mencapai apa yang Anda inginkan di biola Anda?
jeum
5

Solusi Vanilla sederhana lainnya berdasarkan jawaban A1rPun (lihat biolanya untuk solusi jQuery, dan keduanya ada dalam yang ini ).

Tampaknya untuk TIDAK memicu penangan klik-tunggal saat pengguna mengklik dua kali, penangan klik-tunggal harus dipicu setelah penundaan ...

var single = function(e){console.log('single')},
    double = function(e){console.log('double')};

var makeDoubleClick = function(e) {

  var clicks = 0,
      timeout;

  return function (e) {

    clicks++;

    if (clicks == 1) {
      timeout = setTimeout(function () {
        single(e);
        clicks = 0;
      }, 250);
    } else {
      clearTimeout(timeout);
      double(e);
      clicks = 0;
    }
  };
}
document.getElementById('btnVanilla').addEventListener('click', makeDoubleClick(), false);
jeum
sumber
3
Ini memang alternatif terbaik jika Anda tidak ingin satu klik diaktifkan :)
A1rPun
Jika event.detailtersedia, ini adalah cara terbaik untuk mendeteksi klik dua kali dari handler klik. Lihat jawaban ini .
Carl G
5

Berikut adalah alternatif kode jeum untuk jumlah kejadian yang berubah-ubah:

 var multiClickHandler = function (handlers, delay) {
    var clicks = 0, timeout, delay = delay || 250;
    return function (e) {
      clicks++;
      clearTimeout(timeout);
      timeout = setTimeout(function () {
        if(handlers[clicks]) handlers[clicks](e);
        clicks = 0;
      }, delay);
    };
  }

  cy.on('click', 'node', multiClickHandler({
    1: function(e){console.log('single clicked ', e.cyTarget.id())},
    2: function(e){console.log('double clicked ', e.cyTarget.id())},
    3: function(e){console.log('triple clicked ', e.cyTarget.id())},
    4: function(e){console.log('quadro clicked ', e.cyTarget.id())},
    // ...
  }, 300));

Membutuhkan ini untuk aplikasi cytoscape.js .

nex
sumber
Bagus! kita juga bisa mendeklarasikan variabel baru di dalam fungsi yang dikembalikan dan menugaskannyathis , yang merupakan elemen yang diklik, dan meneruskannya ke penangan (di samping eatau sebagai gantinya).
HeyJude
5

Bagaimana cara membedakan antara klik tunggal dan klik ganda pada satu elemen yang sama?

Jika Anda tidak perlu mencampurnya, Anda dapat mengandalkan clickdandblclick dan masing-masing akan melakukan pekerjaan dengan baik.

Masalah muncul saat mencoba mencampurnya: suatu dblclickperistiwa sebenarnya akan memicu suatu clickperistiwa juga , sehingga Anda perlu untuk menentukan apakah satu klik adalah "berdiri sendiri" satu klik, atau bagian dari klik dua kali.

Selain itu: Anda tidak boleh menggunakan keduanya clickdan dblclickpada satu elemen yang sama :

Tidak disarankan untuk mengikat penangan ke kejadian click dan dblclick untuk elemen yang sama. Urutan peristiwa yang dipicu bervariasi dari browser ke browser, dengan beberapa menerima dua peristiwa klik sebelum dblclick dan yang lainnya hanya satu. Sensitivitas klik dua kali (waktu maksimum antara klik yang dideteksi sebagai klik dua kali) dapat bervariasi menurut sistem operasi dan browser, dan seringkali dapat dikonfigurasi oleh pengguna.
Sumber: https://api.jquery.com/dblclick/

Sekarang kabar baiknya:

Anda dapat menggunakan detailproperti acara untuk mendeteksi jumlah klik yang terkait dengan acara tersebut. Ini membuat klik dua kali di dalamclick cukup mudah untuk dideteksi.

Masalahnya tetap mendeteksi klik tunggal dan apakah itu bagian dari klik ganda atau bukan. Untuk itu, kami kembali menggunakan timer dansetTimeout .

Membungkus semuanya, dengan menggunakan atribut data (untuk menghindari variabel global) dan tanpa perlu menghitung klik sendiri, kita mendapatkan:

HTML:

<div class="clickit" style="font-size: 200%; margin: 2em; padding: 0.25em; background: orange;">Double click me</div>

<div id="log" style="background: #efefef;"></div>

JavaScript:

<script>
var clickTimeoutID;
$( document ).ready(function() {

    $( '.clickit' ).click( function( event ) {

        if ( event.originalEvent.detail === 1 ) {
            $( '#log' ).append( '(Event:) Single click event received.<br>' );

            /** Is this a true single click or it it a single click that's part of a double click?
             * The only way to find out is to wait it for either a specific amount of time or the `dblclick` event.
             **/
            clickTimeoutID = window.setTimeout(
                    function() {
                        $( '#log' ).append( 'USER BEHAVIOR: Single click detected.<br><br>' );
                    },
                    500 // how much time users have to perform the second click in a double click -- see accessibility note below.
                );

        } else if ( event.originalEvent.detail === 2 ) {
            $( '#log' ).append( '(Event:) Double click event received.<br>' );
            $( '#log' ).append( 'USER BEHAVIOR: Double click detected.<br>' );
            window.clearTimeout( clickTimeoutID ); // it's a dblclick, so cancel the single click behavior.
        } // triple, quadruple, etc. clicks are ignored.

    });

});
</script>

Demo:

JSfiddle


Catatan tentang aksesibilitas dan kecepatan klik dua kali:

  • Seperti yang dikatakan Wikipedia, "Penundaan maksimum yang diperlukan untuk dua klik berturut-turut untuk ditafsirkan sebagai klik dua kali tidak distandarkan."
  • Tidak ada cara untuk mendeteksi kecepatan klik dua kali sistem di browser.
  • Tampaknya defaultnya adalah 500 ms dan kisaran 100-900mm di Windows ( sumber )
  • Pikirkan orang-orang dengan disabilitas yang menyetel, dalam pengaturan OS mereka, kecepatan klik ganda ke yang paling lambat.
    • Jika kecepatan klik ganda sistem lebih lambat dari kecepatan default kami yang 500 md di atas, perilaku klik tunggal dan ganda akan dipicu.
    • Baik tidak menggunakan mengandalkan gabungan klik tunggal dan ganda pada satu dan item yang sama.
    • Atau: tambahkan pengaturan dalam opsi untuk memiliki kemampuan untuk meningkatkan nilai.

Butuh beberapa saat untuk menemukan solusi yang memuaskan, saya harap ini membantu!

Fabien Snauwaert
sumber
4

Gunakan plugin jQuery Sparkle yang luar biasa. Plugin memberi Anda opsi untuk mendeteksi klik pertama dan terakhir. Anda dapat menggunakannya untuk membedakan antara klik dan dblclick dengan mendeteksi apakah klik lain diikuti oleh klik pertama.

Lihat di http://balupton.com/sandbox/jquery-sparkle/demo/

Hussein
sumber
3

Saya menulis plugin jQuery sederhana yang memungkinkan Anda menggunakan acara 'singleclick' khusus untuk membedakan satu klik dari klik dua kali:

https://github.com/omriyariv/jquery-singleclick

$('#someDiv').on('singleclick', function(e) {
    // The event will be fired with a small delay.
    console.log('This is certainly a single-click');
}
omriyariv.dll
sumber
3

Jawaban modern yang benar adalah campuran antara jawaban yang diterima dan solusi @kyw. Anda memerlukan waktu tunggu untuk mencegah klik tunggal pertama dan event.detailpemeriksaan untuk mencegah klik kedua.

const button = document.getElementById('button')
let timer
button.addEventListener('click', event => {
  if (event.detail === 1) {
    timer = setTimeout(() => {
      console.log('click')
    }, 200)
  }
})
button.addEventListener('dblclick', event => {
  clearTimeout(timer)
  console.log('dblclick')
})
<button id="button">Click me</button>


sumber
1

Saya suka menghindari jquery (dan 90-140k libs lainnya), dan seperti yang dicatat browser menangani onclick terlebih dahulu, jadi inilah yang saya lakukan di situs web yang saya buat (contoh ini juga mencakup mendapatkan lokasi yang diklik xy lokal)

clicksNow-0; //global js, owell

function notify2(e, right) {  // called from onclick= and oncontextmenu= (rc)
var x,y,xx,yy;
var ele = document.getElementById('wrap');  
    // offset fixed parent for local win x y
var xxx= ele.offsetLeft;
var yyy= ele.offsetTop;

//NScape
if (document.layers || document.getElementById&&!document.all) {
    xx= e.pageX;
    yy= e.pageY;
} else {
    xx= e.clientX;
    yy= e.clientY;
}
x=xx-xxx;
y=yy-yyy;

clicksNow++;
    // 200 (2/10ths a sec) is about a low as i seem to be able to go
setTimeout( "processClick( " + right + " , " + x + " , " + y + ")", 200);
}

function processClick(right, x, y) {
if (clicksNow==0) return; // already processed as dblclick
if (clicksNow==2) alert('dbl');
clicksNow=0;
    ... handle, etc ...
}

semoga membantu

dako
sumber
2
URL ke game Anda sama sekali tidak diperlukan untuk memahami jawaban Anda. Saya menghapusnya agar posting ini tidak dilihat sebagai upaya untuk mengirim spam.
Andrew Barber
1
satu-satunya kekurangan, 200 adalah konstanta ajaib dan dapat secara drastis bervariasi dari pengaturan mouse pengguna di OS
Danubian Sailor
1

Berdasarkan jawaban Adrien Schuler (terima kasih banyak !!!), untuk Datatables.net dan untuk banyak kegunaan, berikut ini modifikasinya:

Fungsi

/**
 * For handle click and single click in child's objects
 * @param {any} selector Parents selector, like 'tr'
 * @param {any} single_click_callback Callback for single click
 * @param {any} double_click_callback Callback for dblclick
 * @param {any} timeout Timeout, optional, 300 by default
 */
jQuery.fn.single_double_click = function (selector, single_click_callback, double_click_callback, timeout) {
    return this.each(function () {
        let clicks = 0;
        jQuery(this).on('click', selector, function (event) {
            let self = this;
            clicks++;
            if (clicks == 1) {
                setTimeout(function () {
                    if (clicks == 1) {
                        single_click_callback.call(self, event);
                    } else {
                        double_click_callback.call(self, event);
                    }
                    clicks = 0;
                }, timeout || 300);
            }
        });
    });
}

Menggunakan

$("#MyTableId").single_double_click('tr',
            function () {   //  Click
                let row = MyTable.row(this);
                let id = row.id();
                let data = row.data();
                console.log("Click in "+id+" "+data);
            },
            function () {   //  DBLClick
                let row = MyTable.row(this);
                let id = row.id();
                let data = row.data();
                console.log("DBLClick in "+id+" "+data);
            }
        );
Dani
sumber
0

ini berhasil untuk saya–

var clicked=0;
function chkBtnClcked(evnt) {
    clicked++;
    // wait to see if dblclick
    if (clicked===1) {
        setTimeout(function() {
            clicked=0;
            .
            .
        }, 300); // test for another click within 300ms
    }
    if (clicked===2) {
        stopTimer=setInterval(function() {
            clicked=0;
            .
            .
        }, 30*1000); // refresh every 30 seconds
    }
}

pemakaian-

<div id="cloneimages" style="position: fixed;" onclick="chkBtnClcked(evnt)"  title="Click for next pic; double-click for slide show"></div>
cneeds
sumber
0

Hanya posting jawaban HTML asli kalau-kalau perlu mudah dan HTML.

<p ondblclick="myFunction()" id = 'id'>Double-click me</p>

Ini tentu saja memiliki opsi Jquery asli. yaitu ... $('#id').attr('ondblclick',function(){...})atau, seperti yang dinyatakan sebelumnya,$('#id').dblclick(function(){...});

JSG
sumber
0

Saya tahu ini sudah tua, tetapi di bawah ini adalah hanya contoh JS dari penghitung loop dasar dengan timer tunggal untuk menentukan klik tunggal vs ganda. Semoga ini membantu seseorang.

var count = 0;
var ele = document.getElementById("my_id");
ele.addEventListener('click', handleSingleDoubleClick, false); 

function handleSingleDoubleClick()
{
  if(!count) setTimeout(TimerFcn, 400); // 400 ms click delay
  count += 1;
}
function TimerFcn() 
{
  if(count > 1) console.log('you double clicked!')
  else console.log('you single clicked')
  count = 0;
}
Tim Moses
sumber