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


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.