пов'язувати подію лише один раз


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 {}); }
Ману,

@Ману ви скопіювали з цієї відповіді
aexl

89

На додаток до відповіді pna, ви можете подумати про те, щоб змінити подію на ім'я, щоб ви не обходили розв’язування всіх подій клацання випадково.

функція someMethod () {
    $ (obj) .unbind ('click.namespace'). bind ('click.namespace', function () {});
}

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


10
Це має бути прийнятою відповіддю. Розв’язування всіх подій клацання може легко порушити речі - особливо якщо це складний проект з великою кількістю jQuery. Дякую за це! Не знав про це просте рішення простору імен !!
Саймон Штейнбергер,

З поточної 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

Або скористайтеся функцією jQuery one (), яка схожа на функцію 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 () та одну () функції, що дасть кращий результат, ніж відтворення подій.

Спеціальні випадки працюють, коли у вас є 2 елементи DOM (батько та дитина). Live () на батьківському вузлі гарантує, що подія буде викликана, а потім викликає один () для динамічної реєстрації події, яка буде виконуватися лише один раз. (це забезпечує подібну функціональність, як рендинги).


One()функція працювала, chromeале не працювала safariв Mac.
Принц на

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, і тип. Це означає, що ви можете зв'язати різні типи обробників з однаковим 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/

Це те саме, що метод "увімкнено", але відрізняється своєю поведінкою, щоб не дотримуватися події для декількох селекторів.

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

1

Ви можете досягти цього за допомогою чистого JS, використовуючи метод addEventListener та його колишній варіант

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

2
Це призводить до незв’язування події після того, як елемент було натиснено один раз. Це не вирішує проблему пов'язаних подій кілька разів.
Топ Кіт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.