Переключение обработчиков кликов в Javascript

у меня есть кнопка HTML, к которой я прикрепляю событие, используя jQuery bind(), например:

$('#mybutton').bind('click', myFirstHandlerFunction);

на myFirstHandlerFunction, Я бы хотел, чтобы этот обработчик заменил себя новым обработчиком,mySecondHandlerFunction, например:

function myFirstHandlerFunction(e) {
    $(this).unbind('click', myFirstHandlerFunction).bind('click', mySecondHandlerFunction);
}

во втором обработчике щелчка,mySecondHandlerFunction, Я хотел бы переключить кнопку обратно в исходное состояние: unbind mySecondHandlerFunction обработчик и подключите исходный обработчик,myFirstHandlerFunction, например:

function mySecondHandlerFunction(e) {
    $(this).unbind('click', mySecondHandlerFunction).bind('click', myFirstHandlerFunction);
}

это отлично работает, за исключением одного маленького подробно: поскольку событие click еще не распространилось через каждый из обработчиков кнопки click, событие click передается в следующий обработчик кнопки click, который является обработчиком, который был только что связан в предыдущем обработчике. Конечный результат mySecondHandlerFunction выполняется сразу после myFirstHandlerFunction выполняется.

эта проблема может быть легко решена путем вызова e.stopPropagation() в каждом обработчике, но это имеет отрицательный побочный эффект отмены любых других обработчиков щелчка, которые возможно, были прикреплены независимо.

есть ли способ безопасно и последовательно переключаться между двумя обработчиками щелчка, не останавливая распространение события щелчка?

6 ответов


обновление: С этой формы toggle() был удален в jQuery 1.9, Решение ниже не работает. См.этот вопрос для альтернативы.

похоже toggle () решит вашу проблему:

$("#mybutton").toggle(myFirstHandlerFunction, mySecondHandlerFunction);

код выше будет регистрироваться myFirstHandlerFunction и mySecondHandlerFunction называться на альтернативной кликов.


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

$('#mybutton').bind('click', myHandlerFunction);
var first = true;

function myHandlerFunction(e) {
    if(first){
        // Code from the first handler here;
    }else{
        // Code from the second handler here;
    }
    first = !first; // Invert `first`
}

это решение является взломом, но это is короткий и сладкий для вашей грубой работы:

$('#myButton').click(function() {
  (this.firstClk = !this.firstClk) ? firstHandler(): secondHandler();
});

это хак, потому что он ставит новое свойство непосредственно на this который является элементом HTML DOM click-target, и это, возможно, не лучшая практика. Тем не менее, это позволяет избежать создания новых глобалов, и его можно использовать без изменений на разных кнопках одновременно.

обратите внимание, что первая часть троичной операции использует =, а не == или ===, то есть это задание, а не сравнение. Обратите внимание также, что при первом нажатии кнопки,this.firstClk не определено, но сразу отрицается, что делает первую часть троичной операции оцениваемой до true в первый раз.

вот рабочая версия:

$('#a > button').click(function() {(this.firstClk = !this.firstClk) ? a1(): a2();});
$('#b > button').click(function() {(this.firstClk = !this.firstClk) ? b1(): b2();});

function a1() {$('#a > p').text('one');}
function a2() {$('#a > p').text('two');}

function b1() {$('#b > p').text('ONE');}
function b2() {$('#b > p').text('TWO');}
div {display: inline-block;width: 10em;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a"><p>not yet clicked</p><button>click</button></div>
<div id="b"><p>NOT YET CLICKED</p><button>CLICK</button></div>

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

function addLocationClickHandler() {
    var addLocationClick = overviewMap.on('click', function (event) {
        addLocationClick.remove();
    })
    $('#locationAddButton').one('click', function (cancelEvent) {
        addLocationClick.remove();
        $('#locationAddButton').on('click', addLocationClickHandler)
    });
}

$('#locationAddButton').on('click', addLocationClickHandler)

Это должно позволить вам поместить что-то еще в раздел, где вы перезаписываете обработчик click и не требуете глобальной переменной.


Это поможет добавить атрибут data-click-state на вашу кнопку

$(document).ready(function(){

$('#mybutton').on('click',function(){

if($(this).attr('data-click-state') == 1) {  
$(this).attr('data-click-state', 0)
myFirstHandlerFunction();

} else {
$(this).attr('data-click-state', 1)
mySecondHandlerFunction();
}

});

});

такой:

$(this).bind('click', myMasterHandler);

handler = 0;

function myMasterHandler(e) {
    if(handler == 0) {
        myFirstHandler(e);
        handler = 1;
    } else {
        mySecondHandler(e);
        handler = 0;
    }
}