Как временно отключить обработчик кликов в jQuery? - PullRequest
62 голосов
/ 12 августа 2009

Скажем, у меня есть что-то вроде следующего, чтобы перехватить событие нажатия кнопки:

$("#button_id").click(function() {
  //disable click event
  //do something
  //re-enable click event
}

Как временно отключить событие нажатия кнопки, пока не закончится обработка исходного нажатия? Обычно я делаю исчезновение элемента div после нажатия кнопки, но если пользователь нажимает кнопку несколько раз быстро, он обрабатывает все эти нажатия до того, как элемент div сможет исчезнуть. Я хочу «отменить» кнопку, чтобы только первый щелчок регистрировался до исчезновения div.

Ответы [ 12 ]

60 голосов
/ 02 августа 2014

Я заметил, что это сообщение было старым, но, похоже, оно в топе Google, и такого рода решение никогда не предлагалось, поэтому я все равно решил опубликовать его.

Вы можете просто отключить события курсора и включить их позже через css. Он поддерживается во всех основных браузерах и может оказаться полезным в некоторых ситуациях.

$("#button_id").click(function() {

   $("#button_id").css("pointer-events", "none");
   //do something
   $("#button_id").css("pointer-events", "auto");
}
37 голосов
/ 12 августа 2009

Это более идиоматическая альтернатива решениям с искусственными переменными состояниями:

$("#button_id").one('click', DoSomething);

function DoSomething() {
  // do something.

  $("#button_id").one('click', DoSomething);
}

Один будет выполняться только один раз (до повторного подключения). Больше информации здесь: http://docs.jquery.com/Events/one

10 голосов
/ 12 августа 2009
$("#button_id").click(function() {
  if($(this).data('dont')==1) return;
  $(this).data('dont',1);
  //do something
  $(this).data('dont',0);
}

Помните, что $ .data () будет работать только для элементов с идентификатором.

6 голосов
/ 10 июля 2015

Вы можете отменить привязку вашего обработчика с помощью .off, но есть предостережение; если вы делаете это, просто предотвратите повторный запуск обработчика, когда он уже запущен, вам нужно отложить повторную привязку обработчика.

Например, рассмотрим этот код, который использует 5-секундный горячий сон, чтобы имитировать что-то синхронное и вычислительно дорогое, выполняемое из обработчика (например, тяжелые манипуляции с DOM):

<button id="foo">Click Me!</div>
<script>
    function waitForFiveSeconds() {
        var startTime = new Date();
        while (new Date() - startTime < 5000) {}
    }
    $('#foo').click(function handler() {
        // BAD CODE, DON'T COPY AND PASTE ME!
        $('#foo').off('click');
        console.log('Hello, World!');
        waitForFiveSeconds();
        $('#foo').click(handler);
    });
</script>

Это не сработает. Как вы можете видеть, если вы попробуете это в в этом JSFiddle , если вы нажмете кнопку, когда обработчик уже выполняется, обработчик будет выполнен второй раз после завершения первого выполнения. Более того, по крайней мере в Chrome и Firefox, это было бы верно, даже если вы не использовали jQuery и использовали addEventListener и removeEventListener для добавления и удаления обработчика вместо этого , Браузер выполняет обработчик после первого щелчка, отменяет привязку и повторную привязку обработчика, и , а затем обрабатывает второй щелчок и проверяет, есть ли обработчик щелчка для выполнения.

Чтобы обойти это, вам нужно отложить повторное связывание обработчика, используя setTimeout, чтобы щелчки, которые происходят во время выполнения первого обработчика, были обработаны до повторного присоединения обработчик.

<button id="foo">Click Me!</div>
<script>
    function waitForFiveSeconds() {
        var startTime = new Date();
        while (new Date() - startTime < 5000) {}
    }
    $('#foo').click(function handler() {
        $('#foo').off('click');
        console.log('Hello, World!');
        waitForFiveSeconds();

        // Defer rebinding the handler, so that any clicks that happened while
        // it was unbound get processed first.
        setTimeout(function () {
            $('#foo').click(handler);
        }, 0);
    });
</script>

Вы можете увидеть это в действии на этом модифицированном JSFiddle .

Естественно, в этом нет необходимости, если то, что вы делаете в своем обработчике, уже асинхронно, поскольку тогда вы уже передаете управление браузеру и позволяете ему сбрасывать все события щелчка, прежде чем перепривязывать свой обработчик. Например, такой код будет хорошо работать без setTimeout вызова:

<button id="foo">Save Stuff</div>
<script>
    $('#foo').click(function handler() {
        $('#foo').off('click');
        $.post( "/some_api/save_stuff", function() {
            $('#foo').click(handler);
        });
    });
</script>
4 голосов
/ 22 апреля 2015

Вы можете сделать это так, как другие люди до меня говорили вам, используя взгляд:

A.) Используйте .data элемента button для совместного использования переменной look (или просто глобальной переменной)

if ($('#buttonId').data('locked') == 1)
    return
$('#buttonId').data('locked') = 1;
// Do your thing
$('#buttonId').data('locked') = 0;

B.) Отключить сигналы мыши

$("#buttonId").css("pointer-events", "none");
// Do your thing
$("#buttonId").css("pointer-events", "auto");

C.) Если это кнопка HTML, ее можно отключить (введите [type = submit] или button)

$("#buttonId").attr("disabled", "true");
// Do your thing
$("#buttonId").attr("disabled", "false");

Но следите за другими темами! Я много раз терпел неудачу, потому что моя анимация (исчезновение или увеличение) занимала одну секунду. Например. fadeIn / fadeOut поддерживает функцию обратного вызова в качестве второго параметра. Если нет другого способа, просто сделайте это, используя setTimeout(callback, delay).

Поздравил, Томас

2 голосов
/ 12 августа 2009

Если #button_id подразумевает стандартную кнопку HTML (например, кнопку отправки), вы можете использовать атрибут «disabled», чтобы сделать кнопку неактивной для браузера.

$("#button_id").click(function() {
    $('#button_id').attr('disabled', 'true');

    //do something

     $('#button_id').removeAttr('disabled');
});   

Однако, возможно, вам следует быть осторожным с порядком, в котором эти вещи могут происходить. Если вы используете команду jquery hide, вы можете включить "$ ('# button_id'). RemoveAttr ('disabled');" как часть обратного вызова, так что это не произойдет, пока скрытие не будет завершено.

[править] пример функции с использованием обратного вызова:

$("#button_id").click(function() {
    $('#button_id').attr('disabled', 'true');
    $('#myDiv').hide(function() { $('#button_id').removeAttr('disabled'); });
});   
0 голосов
/ 23 мая 2019

Я едва столкнулся с этой проблемой, когда пытался отобразить загрузочный счетчик, пока ждал завершения функции. Поскольку я добавлял счетчик в HTML, он будет дублироваться при каждом нажатии кнопки. Если вы не против определения переменной в глобальном масштабе, это хорошо сработало для меня.

    var hasCardButtonBeenClicked = '';
    $(".js-mela-card-button").on("click", function(){  
        if(!hasCardButtonBeenClicked){
            hasCardButtonBeenClicked = true;
            $(this).append('<i class="fa fa-circle-o-notch fa-spin" style="margin-left: 3px; font-size: 15px;" aria-hidden="true"></i>');
        }    
    });

Обратите внимание, все, что я делаю, это объявляю переменную, и, пока ее значение равно null , будут выполняться действия, следующие за щелчком, а затем впоследствии значение переменной будет установлено в значение "true" может быть любым значением, если оно не пустое), дальнейшее отключение кнопки до тех пор, пока браузер не обновится или переменная не будет установлена ​​в значение null.

Оглядываясь назад, возможно, имело бы больше смысла просто установить для переменной hasCardButtonBeenClicked значение «false» для начала, а затем при необходимости чередовать «true» и «false».

0 голосов
/ 13 января 2019

лучше использовать текущее событие и не сохранять обработчик в глобальном обработчике. я получаю текущее событие элемента, затем отсоединяю, затем связываю снова. для обработчика.

var element =  $("#elemid")[0];
var tempHandler = jQuery._data(element)["events"]["click"][0].handler;
$("#elemid").unbind("click");

// do the job that click not suppose to listen;
$("#elemid").bind("click" , tempHandler );

для всего обработчика

var element =  $("#elemid")[0];
var clickHandlerList = jQuery._data(element)["events"]["click"];
var handlerList = [];
for(var i  = 0 ; i <  clickHandlerList .length ; i++) {
    handlerList .push(clickHandlerList [i].handler);
}
$("#elemid").unbind("click");
// do the job that click not suppose to listen;
for(var i  = 0 ; i <  handlerList.length ; i++) {
    // return back all handler to element.
    $("#elemid").bind("click" , handlerList[i]);
}
0 голосов
/ 11 июля 2015

Попробуйте использовать .one()

var button = $("#button"),
  result = $("#result"),
  buttonHandler = function buttonHandler(e) {
    result.html("processing...");
    $(this).fadeOut(1000, function() {
      // do stuff
      setTimeout(function() {
        // reset `click` event at `button`
        button.fadeIn({
          duration: 500,
          start: function() {
            result.html("done at " + $.now());
          }
        }).one("click", buttonHandler);

      }, 5000)
    })
  };

button.one("click", buttonHandler);
#button {
  width: 50px;
  height: 50px;
  background: olive;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div id="result"></div>
<div id="button">click</div>
0 голосов
/ 18 марта 2014

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

$(function () {

        $(".btn-Loading").each(function (idx, elm) {
            $(elm).click(function () {
                //do processing
                if ($(".input-validation-error").length > 0)
                    return;
                $(this).attr("label", $(this).text()).text("loading ....");
                $(this).delay(1000).animate({ disabled: true }, 1000, function () {
                    //original event call
                    $.when($(elm).delay(1000).one("click")).done(function () {
                        $(this).animate({ disabled: false }, 1000, function () {
                            $(this).text($(this).attr("label"));
                        })
                    });
                    //processing finalized
                });
            });
        });
        // and fire it after definition
    }
   );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...