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>
Приветствия
Ответы
Ответ 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();
}