На днях понадобилось решить тривиальную задачу, на которую, к сожалению, ушло много времени. Задача звучит следующим образом:
Как повесить на объект два события click и dblclick, чтобы они отрабатывались правильно
Как я уже писал задача на первый взгляд простая, но как всегда есть подводные камни. Приведу пример:
При двойном клике на наш параграф в консоли вы увидите следующий результат:
Но как же так, спросите Вы, ведь браузер должен понимать разницу между двумя событиями! А вот нет. По сути, браузер понимает эти события вполне логично. Он обрабатывает первый click, потом второй. Затем все же понимает, что разница во времени между кликами очень мала и что это dblclick. На этом этапе срабатывает событие на dblclick. Также данный пример можно увидеть на официальном сайте jQuery.
Мне в голову пришел только один вариант. Это было использование функции setTimeout. Сразу перейдем к примеру:
Из данного примера можно понять, что мы устанавливаем таймер на 500 миллисекунд на событие click. Далее при событии dblclick мы этот таймер отчищаем и не должны увидеть вывод «Fire» в консоле. А вот не тут-то было! Мы увидим такой вот результат:
Начинаем задумываться, что же не так. Вроде же все правильно. Начинаем увеличивать таймаут до пары секунд, но все равно видим сообщение “Fire”! Пытаемся разобраться, в чем же проблема:
И получаем неожиданный для себя результат:
Для тех, кто еще не понял в чем проблема, мы выполняем функцию setTimeout два раза и соответственно Timeout каждый раз увеличивается. Когда мы пытаемся его очистить он очищает только последний. Поэтому у нас остается еще одно событие, которое срабатывает через отведенные полсекунды. Лечится это так:
Или так:
Как результат при клике мы будем видеть нужное нам сообщение «Fire», а при двойном клике «Dblclick».
Задача решена!
Если у кого-то есть идеи по-поводу более изящного решения буду благодарен за комментарии.
Спасибо.
Как повесить на объект два события click и dblclick, чтобы они отрабатывались правильно
Как я уже писал задача на первый взгляд простая, но как всегда есть подводные камни. Приведу пример:
<p>Example</p>
jQuery('p').click(function(){
console.log('Click');
}).dblclick(function(){
console.log('Dblclick');
});
При двойном клике на наш параграф в консоли вы увидите следующий результат:
Click
Click
Dblclick
Но как же так, спросите Вы, ведь браузер должен понимать разницу между двумя событиями! А вот нет. По сути, браузер понимает эти события вполне логично. Он обрабатывает первый click, потом второй. Затем все же понимает, что разница во времени между кликами очень мала и что это dblclick. На этом этапе срабатывает событие на dblclick. Также данный пример можно увидеть на официальном сайте jQuery.
Как же это обойти?
Мне в голову пришел только один вариант. Это было использование функции setTimeout. Сразу перейдем к примеру:
var timeoutId;
jQuery('p').click(function(){
timeoutId = setTimeout('console.log("Fire")', 500);
console.log('Click');
}).dblclick(function(){
clearTimeout(timeoutId);
console.log('Dblclick');
});
Из данного примера можно понять, что мы устанавливаем таймер на 500 миллисекунд на событие click. Далее при событии dblclick мы этот таймер отчищаем и не должны увидеть вывод «Fire» в консоле. А вот не тут-то было! Мы увидим такой вот результат:
Click
Click
Dblclick
Fire
Начинаем задумываться, что же не так. Вроде же все правильно. Начинаем увеличивать таймаут до пары секунд, но все равно видим сообщение “Fire”! Пытаемся разобраться, в чем же проблема:
var timeoutId;
jQuery('p').click(function(){
timeoutId = setTimeout('console.log("Fire")', 500);
console.log('Click Timeout = ' + timeoutId );
}).dblclick(function(){
console.log('Dblclick Timeout = ' + timeoutId );
clearTimeout(timeoutId);
console.log('Dblclick Click Timeout = ' + timeoutId );
});
И получаем неожиданный для себя результат:
Click Timeout = 2
Click Timeout = 3
Dblclick Timeout = 3
Dblclick Click Timeout = 3
Fire
Для тех, кто еще не понял в чем проблема, мы выполняем функцию setTimeout два раза и соответственно Timeout каждый раз увеличивается. Когда мы пытаемся его очистить он очищает только последний. Поэтому у нас остается еще одно событие, которое срабатывает через отведенные полсекунды. Лечится это так:
var timeoutId;
jQuery('p').click(function(){
timeoutId = setTimeout('console.log("Fire")', 500);
}).dblclick(function(){
clearTimeout(timeoutId);
clearTimeout(timeoutId - 1);
console.log('Dblclick');
});
Или так:
var timeoutId;
jQuery('p').click(function(){
if (!timeoutId)
timeoutId = setTimeout('clearTimeout(timeoutId);console.log("Fire")', 500);
}).dblclick(function(){
clearTimeout(timeoutId);
console.log('Dblclick');
});
Как результат при клике мы будем видеть нужное нам сообщение «Fire», а при двойном клике «Dblclick».
Задача решена!
Если у кого-то есть идеи по-поводу более изящного решения буду благодарен за комментарии.
Спасибо.