ผูกเหตุการณ์เพียงครั้งเดียว


104

ฉันมีรหัสต่อไปนี้:

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

someMethod ถูกเรียกสองครั้งและทำให้เหตุการณ์คลิกถูกผูกสองครั้ง ฉันจะผูกมันเพียงครั้งเดียวได้อย่างไร?


คำตอบ:


190

หากคุณสามารถนำไปใช้ได้อาจต้องการดูที่event.preventDefaultและevent.stopPropagation หรือเลิกผูกและผูกแต่ละครั้งภายในวิธีการของคุณเช่น

function someMethod()
{
  $(obj).off('click').on('click', function(e) {
    // put your logic in here 
  });
}

19
โปรดใช้ความระมัดระวังเนื่องจากสิ่งนี้จะยกเลิกการเชื่อมโยงเหตุการณ์การคลิกทั้งหมดและไม่ใช่พฤติกรรมที่ต้องการเสมอไป ตัวอย่างเช่นเมื่อคุณผูกข้อมูลบางอย่างเข้ากับเอกสารคุณต้องการเลิกผูกเฉพาะเหตุการณ์นั้น ๆ เท่านั้นไม่ใช่ทั้งหมด
Mārtiņš Briedis

26
ในกรณีที่คุณไม่ต้องการยกเลิกการเชื่อมโยงเหตุการณ์การคลิกอื่น ๆ โดยไม่ได้ตั้งใจคุณอาจต้องการใช้ function someMethod() { $(obj).off('click.namespace').on('click.namespace', function {}); }
Manu

@Manu ที่คุณคัดลอกมาจากคำตอบนี้
aexl

89

นอกเหนือจากคำตอบของ pna แล้วคุณอาจต้องการคิดถึงการตั้งชื่อเหตุการณ์ของคุณเพื่อที่คุณจะได้ไม่ไปเชื่อมโยงเหตุการณ์การคลิกทั้งหมดโดยไม่ได้ตั้งใจ

function someMethod () {
    $ (obj) .unbind ('click.namespace') ผูก ('click.namespace', function () {});
}

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


10
นี่ควรเป็นคำตอบที่ได้รับการยอมรับ การยกเลิกการเชื่อมโยงเหตุการณ์การคลิกทั้งหมดอาจทำให้สิ่งต่างๆเสียหายได้ง่ายโดยเฉพาะอย่างยิ่งหากเป็นโครงการที่ซับซ้อนซึ่งมี jQuery เกิดขึ้นมากมาย ขอบคุณสำหรับสิ่งนั้น! ไม่ทราบเกี่ยวกับการแก้ปัญหาเนมสเปซง่ายๆนี้ !!
Simon Steinberger

ด้วย jQuery ปัจจุบันควรเป็น$(obj).off()และ$(obj).on()ตามลำดับ มิฉะนั้นเนมสเปซจะช่วยได้และสิ่งนี้ได้ผล ขอบคุณ!
aexl

19

ไม่มีเมธอดในตัวเพื่อตรวจสอบว่าคุณได้ผูกฟังก์ชันนี้ไว้แล้วหรือไม่ คุณสามารถเชื่อมโยงฟังก์ชันการคลิกหลายรายการเข้ากับวัตถุได้ ตัวอย่างเช่น:

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


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

หากคุณทำตามข้างต้นเมื่อวัตถุถูกคลิกมันจะแจ้งเตือนสวัสดีแล้วลาก่อน เพื่อให้แน่ใจว่ามีเพียงฟังก์ชันเดียวเท่านั้นที่เชื่อมโยงกับเหตุการณ์การคลิกให้เลิกผูกตัวจัดการเหตุการณ์การคลิกจากนั้นผูกฟังก์ชันที่ต้องการดังนี้:

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

12

วิธีแก้ปัญหาที่ชัดเจนคืออย่าโทรsomeMethod()ซ้ำสองครั้ง หากคุณไม่สามารถแก้ไขได้คุณสามารถเก็บตัวแปรสถานะไว้เพื่อที่จะผูกเพียงครั้งเดียวดังนี้:

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

หมายเหตุ: สิ่งนี้ใช้คุณสมบัติของฟังก์ชันเองแทนที่จะแนะนำตัวแปรส่วนกลางเพื่อติดตามว่าถูกผูกไว้หรือไม่ คุณยังสามารถใช้คุณสมบัติกับวัตถุนั้นเอง

คุณสามารถดูได้ทำงานที่นี่: http://jsfiddle.net/jfriend00/VHkxu/


11

หรือใช้ฟังก์ชัน one () ของ jQuery ซึ่งคล้ายกับ on () แต่จะยิงเหตุการณ์เพียงครั้งเดียวแม้ว่าคุณจะผูกไว้หลายครั้งก็ตาม

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


8
บางครั้งก็ช่วย แต่บางครั้งคุณต้องการวิธีแก้ปัญหาที่คุณสามารถ: แนบครั้งเดียว แต่ใช้หลาย ๆ
Rzassar

5

jQuery ทำให้การเรียกใช้ฟังก์ชันบางอย่างทำได้ง่ายเพียงครั้งเดียว:

function someMethod()
{

     $(obj).click(function() {});
      this.someMethod = $.noop;
}

1
สิ่งนี้จะใช้ได้เฉพาะในกรณีที่ someMethod เป็นวิธีการของวัตถุหรือฟังก์ชันส่วนกลาง
jcubic

jQuery.noopสั้นกว่าอักขระเพียงตัวเดียวfunction(){}ดังนั้นจึงเป็นเรื่องโง่ที่บอกว่า "ช่วย" ตรงนี้เพียงแค่ให้ฟังก์ชันว่างเปล่า นี่คือตัวอย่างที่ไม่ใช่วิธีการของ jQuery ของโซลูชันทั่วไปนี้:var fn = function(){ fn = function(){}; do stuff; };
1j01

1
@ 1j01 แก้ไขเพื่อใช้$แทน
Esailija

2

นี่เป็นข้อเสนอแนะเนื่องจากฉันไม่ทราบตรรกะของคุณ อาจหรือไม่ได้ผลสำหรับคุณ

ลองรวม jquery live () และหนึ่ง () ฟังก์ชั่นจะให้ผลลัพธ์ที่ดีกว่าการย้อนเหตุการณ์

กรณีพิเศษจะใช้ได้เมื่อคุณมีองค์ประกอบ DOM 2 รายการ (แม่และลูก) Live () ที่โหนดแม่ทำให้แน่ใจว่าเหตุการณ์จะถูกเรียกใช้จากนั้นเรียกหนึ่ง () เพื่อลงทะเบียนเหตุการณ์แบบไดนามิกซึ่งจะดำเนินการเพียงครั้งเดียว (ซึ่งมีฟังก์ชันการทำงานที่คล้ายกันเช่น rebinds)


One()ฟังก์ชั่นการทำงานในchromeแต่ไม่ได้ทำงานในในsafari Mac
Half Blood Prince

2

คุณสามารถเพิ่มคลาส css ให้กับองค์ประกอบที่ถูกผูกแล้วกรองออก:

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

วิธีนี้อาจใช้กับปลั๊กอิน:

  $(obj).not('.datetimepicker-applied')
        .datetimepicker()
        .addClass('datetimepicker-applied');

1
var bound = false;

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

แต่ฉันอาจจะตรวจสอบว่าทำไมจึงถูกเรียกสองครั้งก่อนที่จะทำการแก้ปัญหาบางอย่าง


3
หากคุณกำลังดำเนินการด้วยวิธีนี้ให้พิจารณาโซลูชันของ jfriend00 ที่boundติดอยู่someMethod()แทนที่จะสร้างมลพิษให้กับพื้นที่ชื่อทั่วโลก
ณ กัวลาลัมเปอร์

1

หากคุณต้องการผูกกับวัตถุเพียงครั้งเดียวคุณควรใช้แฟล็กและยึดติดกับวัตถุนั้น

ตัวอย่างเช่น:

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

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

1

คุณสามารถใช้ฟังก์ชันส่วนขยาย jQuery นี้

$.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);
  }
};

แทนที่จะทำเช่นนี้

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

ยาทำอย่างนี้

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

ตอนนี้เมื่อฉันมีฟังก์ชั่นรอบ ๆ

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

และฉันเรียกมันหลายครั้ง

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

ทำเพียงครั้งเดียว

สังเกตว่าส่วนขยายทำงานโดยการตรวจสอบทั้ง uid และ type ซึ่งหมายความว่าคุณสามารถผูกตัวจัดการประเภทต่างๆด้วย uid เดียวกันคุณอาจต้องการหรือไม่ต้องการก็ได้ หากต้องการเปลี่ยนแปลงแก้ไข

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

ด้วยสิ่งที่ชอบ

var dataStr = "handler-"+uid;


1

ฉันยังพยายามใช้วิธีปิดและบน jquery สำหรับการผูกเหตุการณ์เพียงครั้งเดียวกับองค์ประกอบ dom ที่ยังไม่มีอยู่หรือยังไม่ได้สร้างองค์ประกอบ dom

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

รหัสนี้ทำงานไม่ถูกต้อง

ฉันเจอวิธีที่มีกำไรมากนั่นคือวิธี 'หนึ่ง' มีประโยชน์มากเมื่อคุณต้องการผูกเหตุการณ์เพียงครั้งเดียว

คุณสามารถค้นหาเอกสารได้ที่นี่ http://api.jquery.com/one/

สิ่งนี้เหมือนกับ method "on" แต่แตกต่างกันที่ลักษณะการทำงานของมันคือไม่ยึดติดกับเหตุการณ์สำหรับตัวเลือกหลายตัว

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

1

คุณสามารถทำได้ด้วย JS บริสุทธิ์โดยใช้เมธอดaddEventListenerและตัวเลือกครั้งเดียวของเขา

target.addEventListener('click', handler, {once: true});

2
ทำให้เหตุการณ์ไม่ถูกผูกมัดหลังจากที่มีการคลิกองค์ประกอบหนึ่งครั้ง วิธีนี้ไม่ได้แก้ปัญหาเหตุการณ์ที่ถูกผูกมัดหลายครั้ง
Top Cat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.