興味深い状況があります-現在、「展開」ボタンをクリックすると非表示になっているテーブル行があります。展開ボタンを含む元の(隠されていない)行の特定のセルには、クリックすると編集可能になるコンテンツもあります。展開ボタンを取り除き、行をクリックすると編集可能になるフィールドなど、行自体の任意の場所でダブルクリックして行を展開できるようにします。あなたはすでにここで問題を嗅ぐことができます。
行をダブルクリックすると、dblclickが発生する前に2つのクリックイベントが最初に発生します。つまり、フィールドをダブルクリックすると、編集可能なフィールドに変わり、行が展開されます。これを防ぎたいです。ダブルクリックでシングルクリックの発生を防ぎ、シングルクリックで通常どおり実行するようにします。
Event.stopPropagation()の使用は、2つの異なるイベントであるため、明らかに機能しません。
何か案は?
編集(いくつかの準擬似コード):
元のバージョン:
<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>
乾杯
一般的な考え方:
最初のクリックでは、関連する関数(single_click_function()など)を呼び出さないでください。むしろ、一定の時間(xなど)のタイマーを設定します。その期間中に別のクリックが発生しない場合は、single_click_function()に進みます。取得した場合は、double_click_function()を呼び出します
2回目のクリックが受信されると、タイマーはクリアされます。また、xミリ秒が経過するとクリアされます。
ところで、パオロの返事をチェックしてください: ダブルクリックイベントが検出されたときにクリック/マウスアップイベントをキャンセルする必要があります そしてもちろんスレッド全体! :-)
$('#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">
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){
//single click.
}, function(e){
//double click.
}));
カスタムの「シングルクリック」イベントを使用して、シングルクリックとダブルクリックを区別できるシンプルなjQueryプラグインを作成しました。これにより、シングルクリックで入力を編集可能にし、ダブルクリックで入力を展開できるインターフェイスを構築できます。 Windows/OSXファイルシステムの名前変更/オープンUIとよく似ています。
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...
}
この問題は、編集可能なフィールドがクリックされたときにのみ発生するため、イベントの伝播をキャンセルする通常のclick
ハンドラーをその要素にアタッチします( stopPropagation
を参照)。たとえば、dbl-clickが500msであると見なされる2つのクリック間のデフォルト時間(600ms)にタイムアウト(setTimeout(...)
)を設定します [src])。その時点までにdblclick
が発生していない場合(これを検出するフラグとして機能する両方のイベントハンドラーで変数にアクセスできます)、ユーザーが代わりに行を展開し、続行することを想定できますそのアクション...
IMO、これを再考する必要があります。残念ながら、シングルクリックハンドラーは、ユーザーがダブルクリックしようとしているかどうかを知ることができません。
両方のアクションをシングルクリックにすることをお勧めしますが、クリックされたときに編集可能なフィールドから上に伝播しないようにします。
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));
Vanilla javascriptのこの例は動作するはずです。
var timer = 0
var delay = 200
var prevent = false
node.onclick = (evnt) => {
timer = setTimeout(() => {
if(!prevent){
//Your code
}
prevent = false
}, delay)
}
node.ondblclick = (evnt) => {
clearTimeout(timer)
prevent=true
//Your code
}
@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);
}
}
})();
}