Як перевірити, чи подія натискання вже пов'язана - JQuery


130

Я пов'язую подію натискання кнопкою:

$('#myButton').bind('click',  onButtonClicked);

За одним сценарієм, це викликається кілька разів, тому коли я роблю, triggerя бачу декілька викликів ajax, які я хочу запобігти.

Як мені робити, bindякщо його раніше не зв'язали.


1
Людина, я думаю + Konrad Гарус має найбезпечніший anwser ( stackoverflow.com/a/6930078/842768 ), слід змінити прийнятий відповідь. Ура! ОНОВЛЕННЯ: Перевірте також коментар Герберта Петерса! Це найкращий підхід.
giovannipds

Поточні стандарти див. У відповіді @A Morel нижче ( stackoverflow.com/a/50097988/1163705 ). Менше кодування і виймає з рівняння всі роботи на здогадки, алгоритми та / або пошук існуючих елементів.
Ксандор

Відповіді:


117

Оновлення 24 серпня '12 : У jQuery 1.8 більше не можна отримати доступ до подій елемента за допомогою .data('events'). (Детальну інформацію див. У цій помилці .) Можна отримати доступ до тих самих даних jQuery._data(elem, 'events'), що є внутрішньою структурою даних, яка не є документацією та, таким чином, не на 100% гарантовано залишається стабільною. Однак це не повинно бути проблемою, і відповідний рядок коду плагіна вище може бути змінено на таке:

var data = jQuery._data(this[0], 'events')[type];

Події jQuery зберігаються в об'єкті даних, який називається events, так що ви можете шукати в цьому:

var button = $('#myButton');
if (-1 !== $.inArray(onButtonClicked, button.data('events').click)) {
    button.click(onButtonClicked);
}

Звичайно, було б найкраще, якби ви змогли структурувати свою програму, щоб цей код викликався лише один раз.


Це може бути інкапсульовано у плагін:

$.fn.isBound = function(type, fn) {
    var data = this.data('events')[type];

    if (data === undefined || data.length === 0) {
        return false;
    }

    return (-1 !== $.inArray(fn, data));
};

Ви можете зателефонувати:

var button = $('#myButton');
if (!button.isBound('click', onButtonClicked)) {
    button.click(onButtonClicked);
}

10
+1 для редагування Читаючи цю публікацію сьогодні, я використовую 1.8. Дякую.
Gigi2m02

2
Дякуємо за редагування Це лише для кнопок чи я можу також використовувати його <a>? Тому що, коли я намагаюся, це говорить про jQuery._data()таку помилкуTypeError: a is undefined
Хоуман

Я б загорнув рядок var data = jQuery._data(this[0], 'events')[type];у спробу лову і повернув помилку в лові. Якщо жодна подія не пов'язана з цим [0], то виклик до [type] призведе до певного варіанту "Неможливо отримати властивість" click "невизначеної або нульової посилання", і, очевидно, це також говорить вам, що вам потрібно знати.
Робб Вандав'єр

Я не впевнений, чи змінився об’єкт _data в jQuery 2.0.3, але я не зміг використовувати для цього $ .inArray. Функція, яку ви хочете порівняти, є властивістю кожного елемента даних, який називається "обробник". Я змінив його для використання простого для оператора і перевірив на еквівалентність рядків, що я припускаю, що це зробив вArray. for (var i = 0; i < data.length; i++) { if (data[i].handler.toString() === fn.toString()) { return true; } }
Робб Вандав'єр

чому б не перенести оновлення / редагування вгору? ... Це фактично правильна відповідь.
Дон Чіддл

179

Ще один спосіб - позначте такі кнопки класом CSS та фільтром:

$('#myButton:not(.bound)').addClass('bound').bind('click',  onButtonClicked);

В останніх версіях jQuery замінюють bindна on:

$('#myButton:not(.bound)').addClass('bound').on('click',  onButtonClicked);

4
Відмінно! Дякую Конраду, це потрапляє в солодке місце. Я люблю елегантні та прості підходи, як це. Я впевнений, що він також більш ефективний, оскільки кожен окремий елемент (до якого вже додані обробники подій кліків) не повинен здійснювати повний пошук у великому відрі подій, порівнюючи кожен з них. У своїй реалізації я назвав доданий допоміжний клас "прив'язаним до натискання", що, на мою думку, є більш доцільним варіантом: $ (". List-item: not (.click-linked)"). AddClass ("прив'язаний до натискання") ;
Ніколас Петерсен

1
Як було сказано у прийнятій відповіді: "Найкраще було б, звичайно, якби ви змогли структурувати свою заявку, щоб цей код викликався лише один раз". Це досягає цього.
Jeff Dege

+1 у моїй ситуації, вимкнено / увімкнено, а також прив’язати / відв'язати перешкоджало численним дзвінкам Це було рішення, яке спрацювало.
Jay

2
Це краще рішення для продуктивності, оскільки код може перевірити наявність класу CSS і ковзання прив'язки вже присутнього. Інші рішення виконують процес відв’язування-повторного зв’язування (хоча б fr4om, що я можу сказати) більше накладних витрат.
Філ Микола

1
2 випуски. (при використанні його в плагіні, який може бути пов'язаний з декількома елементами) Не буде працювати при прив'язці події зміни розміру до об’єкта вікна. Використовувати дані ('прив’язаний', 1) замість addClass ('прив’язаний') - це ще один підхід, який працює. Під час знищення події це може бути зроблено, тоді як від цього залежать інші екземпляри. Тому доцільно перевірити, чи використовуються інші екземпляри.
Герберт Пітерс

59

Якщо використовується jQuery 1.7+:

Ви можете зателефонувати offраніше on:

$('#myButton').off('click', onButtonClicked) // remove handler
              .on('click', onButtonClicked); // add handler

Якщо ні:

Ви можете просто від’єднати це першою подією:

$('#myButton').unbind('click', onButtonClicked) //remove handler
              .bind('click', onButtonClicked);  //add handler

1
Це не дуже гарне рішення, але це буде покращено тільки скасовуючи в один обробник: .unbind('click', onButtonClicked). Дивіться інструкцію
lonesomeday

16
Ви можете насправді простору імен ваших обробників, коли ви додаєте їх, тоді розв’язування стає досить простим. $(sel).unbind("click.myNamespace");
Марк

@lonesomeday, чи ваш приклад із використанням "unbind" означав показати щось інше? Чи не .unbind фактично те саме, що і .off, тому вам доведеться писати$('#myButton').unbind('click', onButtonClicked).bind('click', onButtonClicked);
Джим

1
@Jim Ви побачите, що питання було відредаговане через три роки після мого коментаря! (А також через хвилини одразу після мого коментаря. Вмісту, який я коментував, більше не існує, через що, мабуть, це не має великого сенсу.)
lonesomeday

@lonesomeday hmmm Я не впевнений, чому це було відредаговано, ви вважаєте, я повинен відкатати?
Naftali aka Neal

8

Найкращий спосіб, який я бачу, - це використовувати live () або delegate () для захоплення події в батьківському, а не в кожному дочірньому елементі.

Якщо ваша кнопка знаходиться в # прозорому елементі, ви можете замінити:

$('#myButton').bind('click', onButtonClicked);

від

$('#parent').delegate('#myButton', 'click', onButtonClicked);

навіть якщо #myButton ще не існує, коли цей код виконується.


2
Застарілі методи
dobs

8

Я написав дуже крихітний плагін під назвою "раз", який це зробив. Виконати і ввімкнути елемент.

$.fn.once = function(a, b) {
    return this.each(function() {
        $(this).off(a).on(a,b);
    });
};

І просто:

$(element).once('click', function(){
});

9
.one () скине обробник після першого виконання.
Родольфо Хорхе Немер Ногейра

3
тут "раз" - це один раз для прикріплення обробника. "one" в jquery призначений для запуску один раз, а не приєднання жодного разу
Шишир Арора

1
Я знаю, що я заходжу після факту, але не offвидаляє всіх обробників для даного типу? Значить, якщо був окремий обробник кліків, не пов’язаний, але на тому самому елементі, чи не видалили б його також?
Ксандор

просто використовуйте простір імен для події, щоб воно не скидало всіх обробників типу: 'keypup.test123'
SemanticZen

6

Чому б не використати це

unbind() раніше bind()

$('#myButton').unbind().bind('click',  onButtonClicked);

1
$('#myButton').off().on('click', onButtonClicked);також працює для мене.
Veerakran Sereerungruangkul


Гарний. Для мене чудово працює кнопка, яка вже була прив’язана.
seanbreeden

3

Ось моя версія:

Utils.eventBoundToFunction = function (element, eventType, fCallback) {
    if (!element || !element.data('events') || !element.data('events')[eventType] || !fCallback) {
        return false;
    }

    for (runner in element.data('events')[eventType]) {
        if (element.data('events')[eventType][runner].handler == fCallback) {
            return true;
        }

    }

    return false;
};

Використання:

Utils.eventBoundToFunction(okButton, 'click', handleOkButtonFunction)

2

На основі відповіді @ konrad-garus, але з використанням data, оскільки я вважаю, що її classслід використовувати переважно для стилізації.

if (!el.data("bound")) {
  el.data("bound", true);
  el.on("event", function(e) { ... });
}

2

Щоб уникнути перевірки / прив’язки / відключення, ви можете змінити свій підхід! Чому ви не використовуєте Jquery .on ()?

Оскільки Jquery 1.7, .live (), .delegate () застарілий, тепер ви можете використовувати .on () для

Приєднайте обробник подій для всіх елементів, які відповідають поточному селектору, зараз і в майбутньому

Це означає, що ви можете приєднати подію до вже існуючого батьківського елемента та приєднати дочірні елементи, присутні вони чи ні!

Коли ви використовуєте .on (), як це:

$('#Parent').on('click', '#myButton'  onButtonClicked);

Ви ловите клацання події на батьківському, і він шукає дочірню "#myButton", якщо існує ...

Тож коли ви видаляєте або додаєте дочірній елемент, вам не доведеться турбуватися про те, додавати чи видаляти прив'язку події


Це абсолютно найкраща відповідь на сучасні стандарти. Я не думаю, що ця особливість налаштування обробника на батьків для спостереження за дитиною була добре рекламована, але є досить елегантним рішенням. У мене відбувались пожежі події кілька разів, і кожен раз загальна кількість вистрілених дій постійно збільшувалась. Цей єдиний рядок зробив увесь трюк і без використання .offякого, я вважаю, видалить непов'язані обробники в процесі.
Ксандор


0
if ($("#btn").data('events') != undefined && $("#btn").data('events').click != undefined) {
    //do nothing as the click event is already there
} else {
    $("#btn").click(function (e) {
        alert('test');
    });
}

0

Станом на червень 2019 року я оновив функцію (і вона працює на те, що мені потрібно)

$.fn.isBound = function (type) {
    var data = $._data($(this)[0], 'events');

    if (data[type] === undefined || data.length === 0) {
        return false;
    }
    return true;
};

-2

JQuery має рішення :

$( "#foo" ).one( "click", function() {
  alert( "This will be displayed only once." );
}); 

еквівалент:

$( "#foo" ).on( "click", function( event ) {
  alert( "This will be displayed only once." );
  $( this ).off( event );
});

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