Подтвердить что ты не робот

Javascript с jQuery: нажмите и дважды щелкните по тому же элементу, другой эффект, один отключит другой

У меня интересная ситуация. У меня есть строка таблицы, которая в настоящее время показывает ее скрытую копию, когда я нажимаю кнопку "Развернуть". Исходная (незакрытая) строка, содержащая кнопку расширения, также имеет некоторое содержимое в определенной ячейке, которая при нажатии становится доступной для редактирования. Я хотел бы избавиться от кнопки expand и включить расширение строки с помощью doubleclick в любом месте самой строки, включая поле, которое становится редактируемым при нажатии на него. Вы можете почувствовать здесь неприятности.

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

Использование event.stopPropagation() явно не будет работать, поскольку это два разных события.

Любые идеи?

Изменить (некоторый полу-псевдокод):

Оригинальная версия:

<table>
    <tbody>
        <tr>
            <td><a href="javascript:$('#row_to_expand').toggle();" title="Expand the hidden row">Expand Row</a></td>
            <td>Some kind of random data</td>
            <td><?= $editable_cell_which_turns_into_an_input_field_on_single_click[0]->value("First editable value") ?></td>
            <td><?= $editable_cell_which_turns_into_an_input_field_on_single_click[1]->value("Second editable value") ?></td>
            <td><?= $editable_cell_which_turns_into_an_input_field_on_single_click[2]->value("Third editable value") ?></td>
            <!-- ... -->
            <td><?= $editable_cell_which_turns_into_an_input_field_on_single_click[n]->value("Nth editable value") ?></td>
        </tr>
        <tr style="display: none" id="row_to_expand">
            <td colspan="n">Some hidden data</td>
        </tr>
    </tbody>
</table>

Желаемая версия:

<table>
    <tbody>
        <tr ondblclick="$('#row_to_expand').toggle()">
            <td>Some kind of random data</td>
            <td><?= $editable_cell_which_turns_into_an_input_field_on_single_click[0]->value("First editable value") ?></td>
            <td><?= $editable_cell_which_turns_into_an_input_field_on_single_click[1]->value("Second editable value") ?></td>
            <td><?= $editable_cell_which_turns_into_an_input_field_on_single_click[2]->value("Third editable value") ?></td>
            <!-- ... -->
            <td><?= $editable_cell_which_turns_into_an_input_field_on_single_click[n]->value("Nth editable value") ?></td>
        </tr>
        <tr style="display: none" id="row_to_expand">
            <td colspan="n">Some hidden data</td>
        </tr>
    </tbody>
</table>

Приветствия

4b9b3361

Ответ 1

Общая идея:

  • При первом щелчке не вызывайте связанную функцию (скажем single_click_function()). Скорее установите таймер на определенный период времени (скажем, x). Если мы не получим еще один клик в течение этого промежутка времени, перейдите к single_click_function(). Если мы его получим, вызовите double_click_function()

  • Таймер будет очищен после получения второго щелчка. Он также будет очищен после истечения x миллисекунд.

BTW, проверьте ответ Paolo: Необходимо отменить события click/mouseup при обнаружении двойного щелчка и, конечно, вся нить!: -)

Лучший ответ: fooobar.com/questions/69761/...

Ответ 2

Рабочая демонстрация

$('#alreadyclicked').val('no click');
$('td.dblclickable').on('click',function(){
    var $button=$(this);
    if ($button.data('alreadyclicked')){
        $button.data('alreadyclicked', false); // reset
        $('#alreadyclicked').val('no click');

        if ($button.data('alreadyclickedTimeout')){
            clearTimeout($button.data('alreadyclickedTimeout')); // prevent this from happening
        }
        // do what needs to happen on double click. 
        $('#action').val('Was double clicked');
    }else{
        $button.data('alreadyclicked', true);
        $('#alreadyclicked').val('clicked');
        var alreadyclickedTimeout=setTimeout(function(){
            $button.data('alreadyclicked', false); // reset when it happens
            $('#alreadyclicked').val('no click');
            $('#action').val('Was single clicked');
            // do what needs to happen on single click. 
            // use $button instead of $(this) because $(this) is 
            // no longer the element
        },300); // <-- dblclick tolerance here
        $button.data('alreadyclickedTimeout', alreadyclickedTimeout); // store this id to clear if necessary
    }
    return false;
});

очевидно, используйте <td class="dblclickable">

Ответ 3

Проблема возникает только при щелчке редактируемого поля, поэтому присоединяем к этому элементу обычный обработчик click, который отменяет распространение события (см. stopPropagation) и установит тайм-аут (setTimeout(...)), например, 600 мс (время по умолчанию между двумя щелчками, которое считается dbl-кликом, составляет 500 мс [SRC]). Если к этому моменту dblclick не произошло (вы можете иметь var, доступный в обоих обработчиках событий, который действует как флаг для обнаружения этого), тогда вы можете предположить, что пользователь хочет развернуть строку и продолжить это действие...

ИМО, вы должны подумать об этом. Увы, один обработчик клика не может знать, должен ли пользователь дважды щелкнуть.

Я предлагаю сделать оба действия одним кликом и просто не распространяться из редактируемого поля при его нажатии.

Ответ 4

Перепишите user822711 ответ для повторного использования:

  $.singleDoubleClick = function(singleClk, doubleClk) {
    return (function() {
      var alreadyclicked = false;
      var alreadyclickedTimeout;

      return function(e) {
        if (alreadyclicked) {
          // double
          alreadyclicked = false;
          alreadyclickedTimeout && clearTimeout(alreadyclickedTimeout);
          doubleClk && doubleClk(e);
        } else {
          // single
          alreadyclicked = true;
          alreadyclickedTimeout = setTimeout(function() {
            alreadyclicked = false;
            singleClk && singleClk(e);
          }, 300);
        }
      }
    })();
  }

Вызов функции.

$('td.dblclickable').bind('click', $.singleDoubleClick(function(e){
  //click.
}, function(e){
  //double click.
});

Ответ 5

Я написал простой плагин jQuery, который позволяет использовать пользовательское событие "singleclick", чтобы разделить один клик с двойного щелчка. Это позволяет вам построить интерфейс, в котором один клик делает редактируемый вход, а двойной щелчок расширяет его. Так же, как Windows/OSX файловая система переименовать/открыть интерфейс.

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

$('#someInput').on('singleclick', function(e) {
    // The event will be fired with a small delay but will not fire upon a double-click.
    makeEditable(e.target);
}

$('#container').on('dblclick', function(e) {
    // Expand the row...
}

Ответ 6

window.UI = {
  MIN_LAPS_FOR_DBL_CLICK: 200, // msecs

  evt_down:null,
  timer_down:null,
  mousedown:function(evt){
    if( this.evt_down && evt.timeStamp < this.evt_down.timeStamp + this.MIN_LAPS_FOR_DBL_CLICK ){
      clearTimeout(this.timer_down);
      this.double_click(evt); // => double click
    } else {
      this.evt_down   = evt;
      this.timer_down = setTimeout("UI.do_on_mousedown()", this.MIN_LAPS_FOR_DBL_CLICK);
    }
  },
  evt_up:null,
  timer_up:null,
  mouseup:function(evt){
    if( this.evt_up && evt.timeStamp < this.evt_up.timeStamp + this.MIN_LAPS_FOR_DBL_CLICK ){
      clearTimeout(this.timer_up);
    } else {
      this.evt_up   = evt;
      this.timer_up = setTimeout("UI.do_on_mouseup()", this.MIN_LAPS_FOR_DBL_CLICK);
    }
  },
  do_on_mousedown:function(){
    var evt = this.evt_down;
    // Treatment MOUSE-DOWN here
  },
  do_on_mouseup:function(){
    var evt = this.evt_up;
    // Treatment MOUSE-UP here
  },
  double_click:function(evt){
    // Treatment DBL-CLICK here
  }

}

// Then the observers

$('div#myfoo').bind('mousedown',  $.proxy(UI.mousedown, UI));
$('div#myfoo').bind('mouseup',    $.proxy(UI.mouseup, UI));

Ответ 7

Добавляя к ответу @puttyshell, этот код имеет место для функции visualSingleClick. Это выполняется до setTimeout и предназначено для отображения пользователю некоторого визуального действия для действия перед таймаутом, и с этим я могу использовать более высокий тайм-аут. Я использую это на интерфейсе просмотра Google Диска, чтобы показать пользователю, что выбран файл или папка, которые он нажал. Сам Google Диск делает что-то подобное, но не видел его кода.

/* plugin to enable single and double click on same object */
$.singleDoubleClick = function(visualSingleClk, singleClk, doubleClk) {
  return (function() {
    var alreadyclicked = false;
    var alreadyclickedTimeout;

    return function(e) {
      if (alreadyclicked) {
        // double
        alreadyclicked = false;
        alreadyclickedTimeout && clearTimeout(alreadyclickedTimeout);
        doubleClk && doubleClk(e);
      } else {
        // single
        alreadyclicked = true;
        visualSingleClk && visualSingleClk(e);
        alreadyclickedTimeout = setTimeout(function() {
          alreadyclicked = false;
          singleClk && singleClk(e);
        }, 500);
      }
    }
  })();
}

Ответ 8

Существует более элегантный способ решения этой проблемы, если вы используете backbonejs:

    initialize: function(){
        this.addListener_openWidget();
    }

    addListener_openWidget: function(){
        this.listenToOnce( this, 'openWidgetView', function(e){this.openWidget(e)} );
    },

    events: {
        'click #openWidgetLink' : function(e){this.trigger('openWidgetView',e)},
        'click #closeWidgetLink' : 'closeWidget'
    },

    openWidget: function( e ){
       //Do your stuff
    },

    closeWidget: function(){
       this.addListener_openWidget();
    }