Як розмежувати подію одного клацання та події подвійного клацання?


116

У мене є одна кнопка в li з id "my_id". Я додав два події jQuery з цим елементом

1.

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

2.

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

Але кожен раз це дає мені своє single click


Одноразове натискання завжди доведеться запускати, неможливо дізнатися, чи відбудеться подвійне клацання, якщо воно насправді не відбудеться протягом визначеного часу подвійного клацання.
Пітер Гермішуйс

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подію
Jon z

1
Так, я думаю, ти маєш рацію, dblclickце остаточний шлях сьогодні. jQuery також обробляє цю подію: api.jquery.com/dblclick
Адрієн Шулер

14
@AdrienSchuler - З документа, який ви посилаєте: Не доцільно прив'язувати обробники як до подій клацання, так і до dblclick для одного елемента. Питання в тому, щоб мати обоє .
Альваро Гонсалес

Коли event.detailце доступно, це найкращий спосіб виявити подвійне клацання від обробника кліків. Дивіться цю відповідь .
Карл Г

Приємне рішення Адрієн, мені це потрібно для випадку, коли у нас на одному об'єкті є подія одинарного та подвійного клацання, і лише один повинен бути звільнений. Тому ваше рішення ідеально для мене. Я просто трохи покращив його, щоб взяти "це" під контроль: playcode.io/492022
LOstBrOkenKeY

79

Поведінка dblclickподії пояснюється в Quirksmode .

Порядок подій для a dblclick:

  1. замусоване
  2. миша
  3. клацніть
  4. замусоване
  5. миша
  6. клацніть
  7. dblclick

Єдиним винятком із цього правила є (звичайно) Internet Explorer зі своїм власним порядком:

  1. замусоване
  2. миша
  3. клацніть
  4. миша
  5. dblclick

Як бачите, прослуховування обох подій разом на одному елементі призведе до додаткових дзвінків до вашого clickобробника.


не впевнений, dblclickце навіть надійно ... якщо я натискаю один раз ... зачекайте секунду чи дві, потім натисніть ще раз, я отримаю dblclickподію на другий клацання!
Майкл

Такі довгі кліки корисні, наприклад, для перейменування файлів. Було б добре, якби для розрізнення існували параметр типу 'longClick'.
PeterM

1
Коли event.detailце доступно, це найкращий спосіб виявити подвійне клацання від обробника кліків. Дивіться цю відповідь .
Карл Г

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 / ...

Просто примітка про доступність: якщо подія клацання запускається клавіатурою (наприклад, коли користувач вкладає кнопку фокусування кнопки та натискає клавішу Enter), подія генерується із властивістю деталі як 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 (хоча для роботи з dbl та синглом хрому цей хак не потрібен).
переможець

використання el.dataset.dblclickбуло б приємніше зробити це зараз.
РОБОТИ

Коли event.detailце доступно, це найкращий спосіб виявити подвійне клацання від обробника кліків. Дивіться цю відповідь .
Карл Г

12

Я боюся, що поведінка залежить від браузера:

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

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

Запускаючи свій код у Firefox, попередження () в click()оброблювальній машині не дозволяє вдруге клацнути. Якщо ви видалите таке попередження, ви отримаєте обидві події.


Коли event.detailце доступно, це найкращий спосіб виявити подвійне клацання від обробника кліків. Дивіться цю відповідь .
Карл Г

11

Ну а для подвійного клацання (клацання двічі) спочатку потрібно клацнути один раз. У click()пожежах обробника на перший клацання, і так як попередження спливає, ви не маєте шанс зробити другий клацання , щоб стріляти в dblclick()обробник.

Змініть обробників, щоб зробити щось інше, ніж те, alert()і ви побачите поведінку. (можливо, змінити колір фону елемента):

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

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

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


2
Код, наведений вище, та версія вашої гри "Ваніль" не працюють ... ось виправлена ​​версія ванілі: jsfiddle.net/jeum/cpbwx5vr/19
1616

@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);

3
Це дійсно найкраща альтернатива, якщо ви не хочете, щоб
увімкнути

Коли event.detailце доступно, це найкращий спосіб виявити подвійне клацання від обробника кліків. Дивіться цю відповідь .
Карл Г

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 .


Приємно! ми також можемо оголосити нову змінну всередині повернутої функції та призначити її this, яка є клацаючим елементом, і передати її обробнику (поруч eабо замість неї).
HeyJude

5

Як розмежовувати один клік та подвійний клік на одному і тому ж елементі?

Якщо вам не потрібно змішувати їх, ви можете розраховувати на clickіdblclick кожен буде робити свою роботу дуже добре.

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

Крім того: ви не повинні використовувати як clickі dblclickодин і той же елемент :

Не доцільно прив'язувати обробники як до подій клацання, так і до 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');
}

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-140k libs), і, як зазначають, браузери спочатку обробляють 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 ...
}

сподівання, що допомагає


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>

0

Просто опублікуйте нативну відповідь HTML на всякий випадок, якщо це буде просто та HTML.

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

Звичайно, в цьому варіанті є рідні варіанти Jquery. тобто ... $('#id').attr('ondblclick',function(){...})або, як було сказано раніше,$('#id').dblclick(function(){...});


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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.