mengikat acara hanya sekali

104

Saya memiliki kode berikut:

function someMethod()
{
  $(obj).click(function {});
}

someMethod dipanggil dua kali dan dengan demikian peristiwa klik diikat dua kali. Bagaimana saya bisa membuatnya mengikat hanya sekali?

burung api
sumber
kemungkinan duplikat model peristiwa JQuery dan mencegah penangan duplikat
Cees Timmerman

Jawaban:

190

Jika Anda dapat menerapkannya, mungkin ingin melihat event.preventDefault dan event.stopPropagation OR unbind and bind setiap kali, dalam metode Anda seperti

function someMethod()
{
  $(obj).off('click').on('click', function(e) {
    // put your logic in here 
  });
}
pna
sumber
19
Hati-hati, karena tindakan ini melepaskan SEMUA peristiwa klik, dan tidak selalu perilaku yang diinginkan. Misalnya, saat Anda mengikat sesuatu ke dokumen, Anda ingin melepaskan hanya satu kejadian itu, tidak semuanya.
Mārtiņš Briedis
26
Jika Anda tidak ingin secara tidak sengaja melepaskan peristiwa klik lainnya, Anda mungkin ingin menggunakan function someMethod() { $(obj).off('click.namespace').on('click.namespace', function {}); }
Manu
@Manu yang Anda salin dari jawaban ini
aexl
89

Selain jawaban pna, Anda mungkin ingin memikirkan tentang namespacing acara Anda sehingga Anda tidak terus-menerus melepaskan semua peristiwa klik secara tidak sengaja.

function someMethod () {
    $ (obj) .unbind ('click.namespace'). bind ('click.namespace', function () {});
}

https://api.jquery.com/event.namespace/

Iain
sumber
10
Ini harus menjadi jawaban yang diterima. Melepas semua peristiwa klik dapat merusak banyak hal dengan mudah - terutama jika ini adalah proyek yang kompleks dengan banyak jQuery yang sedang berlangsung. Terima kasih untuk itu! Tidak tahu tentang solusi namespace sederhana ini !!
Simon Steinberger
Dengan jQuery saat ini, ini harus $(obj).off()dan $(obj).on()masing - masing. Jika tidak, namespacing membantu dan ini berhasil. Terima kasih!
aexl
19

Tidak ada metode bawaan untuk menentukan apakah Anda telah mengikat fungsi khusus ini. Anda dapat mengikat beberapa fungsi klik ke sebuah objek. Sebagai contoh:

$('#id').bind('click', function(){
alert('hello');
});


$('#id').bind('click', function(){
alert('goodbuy');
});

jika Anda melakukan hal di atas saat objek diklik itu akan memberi tahu halo lalu selamat tinggal. Untuk memastikan hanya satu fungsi yang terikat ke peristiwa klik lepaskan penangan peristiwa klik lalu ikat fungsi yang diinginkan seperti ini:

$(obj).unbind('click').bind('click', function(){... });
Matt Paxton
sumber
12

Solusi yang jelas adalah tidak menelepon someMethod()dua kali. Jika Anda tidak dapat memperbaikinya, maka Anda dapat menyimpan variabel status sehingga hanya akan mengikat sekali seperti ini:

function someMethod()
{
    if (!someMethod.bound) {
        $(obj).click(function() {});
        someMethod.bound = true;
    }
}

Catatan: ini menggunakan properti dari fungsi itu sendiri daripada memperkenalkan variabel global untuk melacak apakah itu terikat. Anda juga bisa menggunakan properti pada objek itu sendiri.

Anda dapat melihatnya bekerja di sini: http://jsfiddle.net/jfriend00/VHkxu/ .

jfriend00
sumber
11

Atau gunakan fungsi one () jQuery yang mirip dengan on () tetapi hanya mengaktifkan peristiwa sekali, bahkan jika Anda mengikatnya beberapa kali.

http://api.jquery.com/one/

xandrw
sumber
8
Terkadang itu membantu. tetapi terkadang Anda menginginkan solusi di mana Anda dapat: LAMPIRKAN SEKALI TAPI MENGGUNAKAN BANYAK.
Rzassar
5

jQuery memungkinkan pemanggilan beberapa fungsi hanya sekali cukup mudah:

function someMethod()
{

     $(obj).click(function() {});
      this.someMethod = $.noop;
}
Esailija
sumber
1
Ini hanya akan berfungsi jika someMethod adalah metode objek atau fungsi global.
jcubic
jQuery.noophanya satu karakter lebih pendek dari function(){}, jadi agak konyol mengatakan itu "membantu" di sini, hanya menyediakan fungsi kosong. Berikut adalah contoh non-metode non-jQuery dari solusi umum ini:var fn = function(){ fn = function(){}; do stuff; };
1j01
1
@ 1j01 Diedit untuk digunakan $sebagai gantinya
Esailja
2

Ini saran karena saya tidak tahu logika Anda. Mungkin berhasil atau tidak untuk Anda.

Coba gabungkan fungsi jquery live () dan one () akan memberi Anda hasil yang lebih baik daripada event rebinds.

Kasus khusus berfungsi ketika Anda memiliki 2 elemen DOM (induk & anak). Live () di node induk memastikan acara akan dipanggil, dan kemudian memanggil satu () untuk mendaftarkan acara secara dinamis yang akan dijalankan hanya sekali. (ini menyediakan fungsionalitas serupa seperti rebind).

Bambu
sumber
One()fungsi berfungsi chrometetapi tidak berfungsi safaridi Mac.
Half Blood Prince
2

Anda dapat menambahkan kelas css ke elemen terikat dan kemudian memfilternya:

function someMethod()
{
    $(obj).not('.click-binded')
          .click(function {})
          .addClass('click-binded');
}

Metode ini dapat digunakan juga untuk plugin:

  $(obj).not('.datetimepicker-applied')
        .datetimepicker()
        .addClass('datetimepicker-applied');
Bakyt Abdrasulov
sumber
1
var bound = false;

function someMethod()
{
    if(!bound)
    {
       $(obj).click(function {});
       bound = true;
    }
}

tapi saya mungkin akan melihat mengapa itu; dipanggil dua kali sebelum membuat beberapa jenis solusi.

Kai Qing
sumber
3
Jika Anda pergi dengan cara ini pertimbangkan solusi jfriend00 di mana bounddilampirkan someMethod()alih-alih mencemari ruang nama global.
nuala
1

Jika Anda ingin mengikat objek hanya sekali, Anda harus mengimplementasikan sebuah bendera dan menempel pada objek itu.

Sebagai contoh:

if($('#id') && $('#id').data('done') == null)) {
    $('#id').bind('click', function() {
        alert('hello');
    });

    $('#id').data('done', true);
}
cscan
sumber
1

Anda dapat menggunakan fungsi ekstensi jQuery ini.

$.fn.once = function (type, fn, uid) {
  if(uid == undefined) {
    console.error("Called $.once without uid\n", this, "\n", fn);
  }

  var dataStr = type+"-handler-"+uid;
  if(!this.data(dataStr)) {
    this.data(dataStr, true);
    this.on(type, fn);
  }
};

Daripada melakukan ini

$("button").on("click", function(){
  alert("You Clicked On A Button");
});

Ya lakukan ini

$("button").once("click", function(){
  alert("You Clicked On A Button");
}, "btnHandler");

Sekarang ketika saya memiliki fungsi di sekitarnya

function addBtnHandler() {
  $("button").once("click", function() {
    alert("You Clicked On A Button");
  }, "btnHandler");
}

Dan saya menyebutnya beberapa kali

addBtnHandler();
addBtnHandler();
addBtnHandler();

Itu hanya melakukannya sekali.

Perhatikan bahwa ekstensi bekerja dengan memeriksa uid dan type. Ini berarti Anda dapat mengikat berbagai jenis penangan dengan uid yang sama, Anda mungkin menginginkan ini atau tidak. Untuk mengubahnya, edit.

var dataStr = type+"-handler-"+uid;

Dengan sesuatu seperti

var dataStr = "handler-"+uid;

nathnolt
sumber
1

Saya juga mencoba menggunakan metode off and on jquery untuk mengikat event hanya sekali dengan elemen dom yang belum ada atau elemen dom belum dibuat.

$('.select').off('event').on('event', 'selector', function(e){ // });

Kode ini tidak berfungsi dengan benar

Saya menemukan metode yang sangat menguntungkan yaitu metode 'satu'. Ini sangat berguna jika Anda ingin mengikat acara hanya sekali.

Anda dapat menemukan dokumennya di sini http://api.jquery.com/one/

Ini sama dengan metode 'on' tetapi berbeda dengan perilakunya dengan tidak melekat pada acara untuk banyak pemilih.

$('body').one('click', 'selector', function(){ // do your stuff here });
Ankit Vishwakarma
sumber
1

Anda dapat mencapai ini dengan JS murni, menggunakan metode addEventListener dan opsi sekali

target.addEventListener('click', handler, {once: true});
Skav
sumber
2
Ini menyebabkan acara menjadi tidak terikat setelah elemen diklik satu kali. Ini tidak menyelesaikan masalah acara yang diikat beberapa kali.
Kucing Top