Как отличить событие одиночного щелчка от события двойного щелчка?

117

У меня одна кнопка в li с id "my_id". Я прикрепил к этому элементу два события jQuery

1.

$("#my_id").click(function() { 
    alert('single click');
});

2.

$("#my_id").dblclick(function() {
    alert('double click');
});

Но каждый раз это дает мне single click

user426795
источник
Одиночный щелчок всегда должен срабатывать, невозможно узнать, произойдет ли двойной щелчок, если только он не произойдет в течение указанного времени двойного щелчка.
Pieter Germishuys
7
Это возможно, проверьте мой ответ. Вы должны подождать несколько мс после первого щелчка и проверить, есть ли новый щелчок до указанного времени. Таким образом, вы сможете узнать, является ли это простым или двойным щелчком.
Адриен Шулер

Ответы:

65

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

Вот уловка :

// Author:  Jacek Becela
// Source:  http://gist.github.com/399624
// License: MIT

jQuery.fn.single_double_click = function(single_click_callback, double_click_callback, timeout) {
  return this.each(function(){
    var clicks = 0, self = this;
    jQuery(this).click(function(event){
      clicks++;
      if (clicks == 1) {
        setTimeout(function(){
          if(clicks == 1) {
            single_click_callback.call(self, event);
          } else {
            double_click_callback.call(self, event);
          }
          clicks = 0;
        }, timeout || 300);
      }
    });
  });
}

Использование:

$("button").single_double_click(function () {
  alert("Try double-clicking me!")
}, function () {
  alert("Double click detected, I'm hiding")
  $(this).hide()
})
<button>Click Me!</button>

РЕДАКТИРОВАТЬ:

Как указано ниже, лучше использовать собственное dblclickсобытие: http://www.quirksmode.org/dom/events/click.html

Или тот, который предоставляется jQuery: http://api.jquery.com/dblclick/

Адриен Шулер
источник
14
Может показаться, что в целом это хорошо работает, но разве время задержки между щелчками (при котором два щелчка интерпретируются как двойной щелчок) не отличается от конфигурации системы? Наверное, безопаснее полагаться на dblclickсобытие,
Джон
1
Да, я думаю, ты прав, dblclickэто определенно правильный путь сегодня. jQuery также обрабатывает это событие: api.jquery.com/dblclick
Adrien Schuler
14
@AdrienSchuler - Из документа, на который вы ссылаетесь: нецелесообразно привязывать обработчики к событиям щелчка и dblclick для одного и того же элемента. Вопрос в том, чтобы иметь и то и другое .
Альваро Гонсалес,
Когда event.detailдоступно, это лучший способ обнаружить двойной щелчок в обработчике щелчков. Смотрите этот ответ .
Carl G
Хорошее решение, Адриан, оно мне нужно для случая, когда у нас есть событие одиночного и двойного щелчка на одном объекте, и только один должен быть запущен. Поэтому ваше решение идеально подходит для меня. Я просто немного улучшил его, чтобы контролировать «это»: playcode.io/492022
LOstBrOkenKeY
79

Поведение dblclickсобытия объясняется в Quirksmode .

Порядок событий для a dblclick:

  1. MouseDown
  2. MouseUp
  3. щелкнуть
  4. MouseDown
  5. MouseUp
  6. щелкнуть
  7. DblClick

Единственным исключением из этого правила является (конечно) Internet Explorer с их настраиваемым порядком:

  1. MouseDown
  2. MouseUp
  3. щелкнуть
  4. MouseUp
  5. DblClick

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

Райан
источник
не уверен dblclick, даже надежно ... если я щелкну один раз ... подождите секунду или две, затем щелкните еще раз, я получаю dblclickсобытие при втором щелчке!
Майкл
Такие длинные щелчки полезны, например, для переименования файлов. Было бы неплохо, если бы был параметр типа longClick, чтобы отличать его.
PeterM
1
Когда event.detailдоступно, это лучший способ обнаружить двойной щелчок в обработчике щелчков. Смотрите этот ответ .
Carl G
38

Оказывается, вместо использования дополнительных состояний и setTimeout есть собственное свойство, к detailкоторому вы можете получить доступ из eventобъекта!

element.onclick = event => {
   if (event.detail === 1) {
     // it was a single click
   } else if (event.detail === 2) {
     // it was a double click
   }
};

Современные браузеры и даже IE-9 это поддерживают :)

Источник: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail

кив
источник
Лучший ответ :)
sk8terboi87 ツ
3
В случае двойного щелчка по- event.detail === 1прежнему срабатывает одиночный щелчок (где ). См. Мою скрипку или этот комментарий в этой ветке .
Fabien Snauwaert
Хорошее замечание @FabienSnauwaert. Я полагаю, что мы не можем привязать обработчик событий одиночного и двойного щелчка к конкретному элементу; описанный выше метод полезен для окончательного определения двойного щелчка, не прибегая к таким вещам, как таймер.
kyw
Вам все еще нужен таймер при первом щелчке, чтобы не сработать. Проверьте мой ответ ниже stackoverflow.com/questions/5497073/…
Просто примечание о доступности: если событие щелчка запускается с клавиатуры (например, когда пользователь вкладывает курсор, чтобы сфокусировать кнопку и нажать клавишу ввода), событие генерируется со свойством detail как 0, таким образом, делая что-то вроде if(evt.detail !== 1) return;отклонения случайного двойного щелчки заблокируют доступ к этой кнопке для пользователей без мыши.
gristow
25

Простая функция. Никаких jquery или других фреймворков не требуется. Передайте свои функции как параметры

<div onclick="doubleclick(this, function(){alert('single')}, function(){alert('double')})">click me</div>
    <script>
        function doubleclick(el, onsingle, ondouble) {
            if (el.getAttribute("data-dblclick") == null) {
                el.setAttribute("data-dblclick", 1);
                setTimeout(function () {
                    if (el.getAttribute("data-dblclick") == 1) {
                        onsingle();
                    }
                    el.removeAttribute("data-dblclick");
                }, 300);
            } else {
                el.removeAttribute("data-dblclick");
                ondouble();
            }
        }
    </script>
Ренцо Чио
источник
2
Я думаю, это должен быть лучший ответ. Однако мне пришлось уменьшить тайм-аут до 200, чтобы он работал в Windows IE8, но это значение может зависеть от ОС и пользователя. А также сохранена ссылка на таймер, чтобы иметь возможность отменить выполнение щелчка, если зарегистрирован двойной щелчок.
xpereta
Спасибо за этот фрагмент кода, он отлично работает в chrome и firefox (хотя chrome не требует этого хака для работы с dbl и single).
victor
использование el.dataset.dblclickбыло бы более приятным способом сделать это сейчас.
WORMSS
Когда event.detailдоступно, это лучший способ обнаружить двойной щелчок в обработчике щелчков. Смотрите этот ответ .
Carl G
12

Боюсь, что поведение зависит от браузера:

Не рекомендуется привязывать обработчики одновременно к событиям click и dblclick для одного и того же элемента. Последовательность запускаемых событий различается от браузера к браузеру: одни получают два события щелчка перед dblclick, а другие - только одно. Чувствительность к двойному щелчку (максимальное время между щелчками, которое определяется как двойной щелчок) может варьироваться в зависимости от операционной системы и браузера и часто настраивается пользователем.

http://api.jquery.com/dblclick/

При запуске вашего кода в Firefox предупреждение () в click()обработчике не позволяет вам щелкнуть второй раз. Если вы удалите такое предупреждение, вы получите оба события.

Альваро Гонсалес
источник
Когда event.detailдоступно, это лучший способ обнаружить двойной щелчок в обработчике щелчков. Смотрите этот ответ .
Carl G
11

Итак, чтобы дважды щелкнуть (дважды щелкнуть), вы должны сначала щелкнуть один раз. В click()пожарах обработчика на первый щелчок, и так как предупреждение всплывает, вы не имеете шанс сделать второй щелчок , чтобы стрелять в dblclick()обработчик.

Измените свои обработчики так, чтобы они выполняли что-то иное, кроме как, alert()и вы увидите поведение. (возможно, изменить цвет фона элемента):

$("#my_id").click(function() { 
    $(this).css('backgroundColor', 'red')
});

$("#my_id").dblclick(function() {
    $(this).css('backgroundColor', 'green')
});
bradley.ayers
источник
7

Этот ответ со временем устарел, проверьте решение @kyw.

Я создал решение, вдохновленное сутью, опубликованной @AdrienSchuler. Используйте это решение только в том случае, если вы хотите привязать к элементу одиночный И двойной щелчок. В противном случае рекомендую использовать родные clickи dblclickслушатели.

Вот отличия:

  • Vanillajs, без зависимостей
  • Не дожидайтесь setTimeoutобработки обработчика щелчка или двойного щелчка
  • При двойном щелчке сначала запускается обработчик щелчка, затем обработчик двойного щелчка

Javascript:

function makeDoubleClick(doubleClickCallback, singleClickCallback) {
    var clicks = 0, timeout;
    return function() {
        clicks++;
        if (clicks == 1) {
            singleClickCallback && singleClickCallback.apply(this, arguments);
            timeout = setTimeout(function() { clicks = 0; }, 400);
        } else {
            timeout && clearTimeout(timeout);
            doubleClickCallback && doubleClickCallback.apply(this, arguments);
            clicks = 0;
        }
    };
}

Использование:

var singleClick = function(){ console.log('single click') };
var doubleClick = function(){ console.log('double click') };
element.addEventListener('click', makeDoubleClick(doubleClick, singleClick));

Ниже показано использование в jsfiddle, кнопка jQuery - это поведение принятого ответа.

jsfiddle

A1rPun
источник
2
Приведенный выше код и "Vanilla" версия вашей скрипки не работают ... вот фиксированная версия Vanilla: jsfiddle.net/jeum/cpbwx5vr/19
jeum
@jeum Он по-прежнему помогает мне в каждом браузере. Что «не работает» и чего вы ждете? Похоже, ваша версия не выполняет то, что я задумал.
A1rPun
Кулак Я изменил свою версию (удалено двойное закрытие), попробуйте новую: jsfiddle.net/jeum/cpbwx5vr/20 Проблема с вашей скрипкой (ванильная версия) заключается в том, что двойной щелчок запускает единственный обработчик: он извлекает один + двойной для меня.
jeum
@jeum Это выдает ошибку. Да, мой ответ отличается от принятого и других ответов здесь, и я также указываю это различие в этой строке: нажмите щелчок, затем
двойной щелчок
1
Да, снова ошибка, поэтому эта версия отвечает на главный вопрос: jsfiddle.net/jeum/cpbwx5vr/21 . Теперь что касается вашей версии (правда, я не понял), заметили ли вы, что «jQuery» не достигает того, чего вы хотите в своей скрипке?
jeum
5

Еще одно простое решение Vanilla, основанное на ответе A1rPun (см. Его скрипку для решения jQuery, и оба находятся в этом ).

Кажется, что, чтобы НЕ запускать обработчик одного щелчка, когда пользователь дважды щелкает, обработчик одного щелчка обязательно запускается после задержки ...

var single = function(e){console.log('single')},
    double = function(e){console.log('double')};

var makeDoubleClick = function(e) {

  var clicks = 0,
      timeout;

  return function (e) {

    clicks++;

    if (clicks == 1) {
      timeout = setTimeout(function () {
        single(e);
        clicks = 0;
      }, 250);
    } else {
      clearTimeout(timeout);
      double(e);
      clicks = 0;
    }
  };
}
document.getElementById('btnVanilla').addEventListener('click', makeDoubleClick(), false);
jeum
источник
3
Это действительно лучшая альтернатива, если вы не хотите, чтобы
запускался
Когда event.detailдоступно, это лучший способ обнаружить двойной щелчок в обработчике щелчков. Смотрите этот ответ .
Carl G
5

Вот альтернативный код jeum для произвольного количества событий:

 var multiClickHandler = function (handlers, delay) {
    var clicks = 0, timeout, delay = delay || 250;
    return function (e) {
      clicks++;
      clearTimeout(timeout);
      timeout = setTimeout(function () {
        if(handlers[clicks]) handlers[clicks](e);
        clicks = 0;
      }, delay);
    };
  }

  cy.on('click', 'node', multiClickHandler({
    1: function(e){console.log('single clicked ', e.cyTarget.id())},
    2: function(e){console.log('double clicked ', e.cyTarget.id())},
    3: function(e){console.log('triple clicked ', e.cyTarget.id())},
    4: function(e){console.log('quadro clicked ', e.cyTarget.id())},
    // ...
  }, 300));

Это нужно для приложения cytoscape.js .

NEX
источник
Ницца! мы также можем объявить новую переменную внутри возвращаемой функции и присвоить ее thisэлементу, на который был выполнен щелчок, и передать ее обработчику (вместе eили вместо него).
HeyJude
5

Как отличить одиночный клик от двойного клика по одному и тому же элементу?

Если вам не нужно смешивать их, вы можете рассчитывать на clickи dblclickкаждый будет делать свою работу очень хорошо.

Проблема возникает при попытке смешивать их: событие будет на самом деле вызвать событие , а также , так что вы должны определить , одним нажатием кнопки , является ли «автономным» одним щелчком мыши, или частью двойного щелчка.dblclickclick

Вдобавок: нельзя использовать оба clickи dblclickв одном и том же элементе :

Не рекомендуется привязывать обработчики одновременно к событиям click и dblclick для одного и того же элемента. Последовательность запускаемых событий различается от браузера к браузеру: одни получают два события щелчка перед dblclick, а другие - только одно. Чувствительность к двойному щелчку (максимальное время между щелчками, которое определяется как двойной щелчок) может варьироваться в зависимости от операционной системы и браузера и часто настраивается пользователем.
Источник: https://api.jquery.com/dblclick/

А теперь к хорошим новостям:

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

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

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

HTML:

<div class="clickit" style="font-size: 200%; margin: 2em; padding: 0.25em; background: orange;">Double click me</div>

<div id="log" style="background: #efefef;"></div>

JavaScript:

<script>
var clickTimeoutID;
$( document ).ready(function() {

    $( '.clickit' ).click( function( event ) {

        if ( event.originalEvent.detail === 1 ) {
            $( '#log' ).append( '(Event:) Single click event received.<br>' );

            /** Is this a true single click or it it a single click that's part of a double click?
             * The only way to find out is to wait it for either a specific amount of time or the `dblclick` event.
             **/
            clickTimeoutID = window.setTimeout(
                    function() {
                        $( '#log' ).append( 'USER BEHAVIOR: Single click detected.<br><br>' );
                    },
                    500 // how much time users have to perform the second click in a double click -- see accessibility note below.
                );

        } else if ( event.originalEvent.detail === 2 ) {
            $( '#log' ).append( '(Event:) Double click event received.<br>' );
            $( '#log' ).append( 'USER BEHAVIOR: Double click detected.<br>' );
            window.clearTimeout( clickTimeoutID ); // it's a dblclick, so cancel the single click behavior.
        } // triple, quadruple, etc. clicks are ignored.

    });

});
</script>

Демо:

JSfiddle


Примечания о доступности и скорости двойного щелчка:

  • Как пишет Википедия, «максимальная задержка, необходимая для того, чтобы два последовательных клика интерпретировались как двойной щелчок, не стандартизована».
  • Невозможно определить скорость двойного щелчка системы в браузере.
  • Кажется, что по умолчанию это 500 мс, а диапазон 100-900 мм в Windows ( источник )
  • Подумайте о людях с ограниченными возможностями, которые установили в настройках своей ОС самую низкую скорость двойного щелчка.
    • Если скорость двойного щелчка в системе ниже, чем наши 500 мс по умолчанию, указанные выше, будут срабатывать как одиночный, так и двойной щелчок.
    • Либо не используйте, полагайтесь на комбинированный одиночный и двойной щелчок по одному и тому же элементу.
    • Или: добавьте параметр в параметры, чтобы иметь возможность увеличивать значение.

Потребовалось время, чтобы найти удовлетворительное решение, надеюсь, это поможет!

Фабьен Снауверт
источник
4

Используйте отличный плагин jQuery Sparkle. Плагин дает вам возможность определять первый и последний щелчок. Вы можете использовать его, чтобы различать щелчок и dblclick, определяя, последовал ли за другим щелчком первый щелчок.

Проверьте это на http://balupton.com/sandbox/jquery-sparkle/demo/

Хусейн
источник
3

Я написал простой плагин jQuery, который позволяет вам использовать настраиваемое событие singleclick, чтобы отличать одиночный щелчок от двойного щелчка:

https://github.com/omriyariv/jquery-singleclick

$('#someDiv').on('singleclick', function(e) {
    // The event will be fired with a small delay.
    console.log('This is certainly a single-click');
}
omriyariv
источник
3

Современный правильный ответ - это смесь принятого ответа и решения @kyw. Вам нужен тайм-аут, чтобы предотвратить этот первый щелчок, и event.detailпроверка, чтобы предотвратить второй щелчок.

const button = document.getElementById('button')
let timer
button.addEventListener('click', event => {
  if (event.detail === 1) {
    timer = setTimeout(() => {
      console.log('click')
    }, 200)
  }
})
button.addEventListener('dblclick', event => {
  clearTimeout(timer)
  console.log('dblclick')
})
<button id="button">Click me</button>


источник
1

Мне нравится избегать jquery (и других библиотек размером 90-140 тыс.), И, как уже отмечалось, браузеры сначала обрабатывают onclick, поэтому вот что я сделал на созданном мной веб-сайте (этот пример также касается получения локального xy местоположения по щелчку)

clicksNow-0; //global js, owell

function notify2(e, right) {  // called from onclick= and oncontextmenu= (rc)
var x,y,xx,yy;
var ele = document.getElementById('wrap');  
    // offset fixed parent for local win x y
var xxx= ele.offsetLeft;
var yyy= ele.offsetTop;

//NScape
if (document.layers || document.getElementById&&!document.all) {
    xx= e.pageX;
    yy= e.pageY;
} else {
    xx= e.clientX;
    yy= e.clientY;
}
x=xx-xxx;
y=yy-yyy;

clicksNow++;
    // 200 (2/10ths a sec) is about a low as i seem to be able to go
setTimeout( "processClick( " + right + " , " + x + " , " + y + ")", 200);
}

function processClick(right, x, y) {
if (clicksNow==0) return; // already processed as dblclick
if (clicksNow==2) alert('dbl');
clicksNow=0;
    ... handle, etc ...
}

надеюсь, это поможет

DAKO
источник
2
URL-адрес вашей игры не требуется, чтобы понять ваш ответ. Я удаляю его, чтобы этот пост не рассматривался как попытка спама.
Эндрю Барбер
1
единственный минус, 200 - это магическая константа, которая может сильно отличаться от настроек мыши пользователя в ОС
Danubian Sailor
1

Основываясь на ответе Адриена Шулера (большое спасибо !!!), для Datatables.net и для многих пользователей, вот модификация:

Функция

/**
 * For handle click and single click in child's objects
 * @param {any} selector Parents selector, like 'tr'
 * @param {any} single_click_callback Callback for single click
 * @param {any} double_click_callback Callback for dblclick
 * @param {any} timeout Timeout, optional, 300 by default
 */
jQuery.fn.single_double_click = function (selector, single_click_callback, double_click_callback, timeout) {
    return this.each(function () {
        let clicks = 0;
        jQuery(this).on('click', selector, function (event) {
            let self = this;
            clicks++;
            if (clicks == 1) {
                setTimeout(function () {
                    if (clicks == 1) {
                        single_click_callback.call(self, event);
                    } else {
                        double_click_callback.call(self, event);
                    }
                    clicks = 0;
                }, timeout || 300);
            }
        });
    });
}

Использовать

$("#MyTableId").single_double_click('tr',
            function () {   //  Click
                let row = MyTable.row(this);
                let id = row.id();
                let data = row.data();
                console.log("Click in "+id+" "+data);
            },
            function () {   //  DBLClick
                let row = MyTable.row(this);
                let id = row.id();
                let data = row.data();
                console.log("DBLClick in "+id+" "+data);
            }
        );
Дани
источник
0

это сработало для меня -

var clicked=0;
function chkBtnClcked(evnt) {
    clicked++;
    // wait to see if dblclick
    if (clicked===1) {
        setTimeout(function() {
            clicked=0;
            .
            .
        }, 300); // test for another click within 300ms
    }
    if (clicked===2) {
        stopTimer=setInterval(function() {
            clicked=0;
            .
            .
        }, 30*1000); // refresh every 30 seconds
    }
}

использование-

<div id="cloneimages" style="position: fixed;" onclick="chkBtnClcked(evnt)"  title="Click for next pic; double-click for slide show"></div>
cneeds
источник
0

Просто отправьте собственный HTML-ответ на всякий случай, если нужно, чтобы он был простым и HTML.

<p ondblclick="myFunction()" id = 'id'>Double-click me</p>

Это, конечно, имеет собственные параметры JQuery. т.е. ... $('#id').attr('ondblclick',function(){...})или, как указано ранее,$('#id').dblclick(function(){...});

JSG
источник
0

Я знаю, что это устарело, но ниже представлен только JS-пример простого счетчика цикла с одним таймером для определения одиночного или двойного щелчка. Надеюсь, это кому-то поможет.

var count = 0;
var ele = document.getElementById("my_id");
ele.addEventListener('click', handleSingleDoubleClick, false); 

function handleSingleDoubleClick()
{
  if(!count) setTimeout(TimerFcn, 400); // 400 ms click delay
  count += 1;
}
function TimerFcn() 
{
  if(count > 1) console.log('you double clicked!')
  else console.log('you single clicked')
  count = 0;
}
Тим Моисей
источник