привязать событие только один раз


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
Будьте осторожны, потому что это отключает ВСЕ события щелчка, и это не всегда желаемое поведение. Например, когда вы привязываете что-то к документу, вы хотите отвязать только это одно событие, а не все из них.
Мартиньш Бриедис

26
Если вы не хотите случайно отвязать другие события кликов, вы можете использовать function someMethod() { $(obj).off('click.namespace').on('click.namespace', function {}); }
Ману

@Manu, который вы скопировали из этого ответа
aexl

89

В дополнение к ответу pna вы можете подумать об именовании своего события, чтобы случайно не отвязать все события щелчка.

function someMethod () {
    $ (obj) .unbind ('click.namespace'). bind ('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

Или используйте функцию 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 () и one (), и это даст лучший результат, чем повторные привязки событий.

Особые случаи работают, когда у вас есть 2 элемента DOM (родительский и дочерний). Live () на родительском узле гарантирует, что событие будет вызвано, а затем вызывает one () для динамической регистрации события, которое будет выполнено только один раз. (это обеспечивает аналогичные функции, такие как повторные привязки).


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()вместо того, чтобы загрязнять глобальное пространство имен.
nuala,

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

Я также пытался использовать off и on метод jquery для привязки события только один раз с элементом dom, который еще не существует, или элемент dom еще не создан.

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

Этот код не работал должным образом

Я наткнулся на очень прибыльный метод - «один». Это очень полезно, если вы хотите привязать событие только один раз.

Вы можете найти документ здесь http://api.jquery.com/one/

Это то же самое, что и метод on, но отличается своим поведением: не следует придерживаться события для нескольких селекторов.

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

1

Вы можете добиться этого с чистым JS, используя addEventListener метод и его один раз вариант

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

2
Это приводит к тому, что событие становится несвязанным после однократного щелчка по элементу. Это не решает проблему многократной привязки событий.
Top Cat
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.