webentwicklung-frage-antwort-db.com.de

Javascript mit jQuery: Klicken und doppelklicken Sie auf dasselbe Element, unterschiedliche Effekte, einer deaktiviert den anderen

Ich habe eine interessante Situation - ich habe eine Tabellenzeile, die derzeit das versteckte Gegenstück anzeigt, wenn ich auf die Schaltfläche "Erweitern" klicke. Die ursprüngliche (nicht ausgeblendete) Zeile, in der sich die Erweiterungsschaltfläche befindet, enthält auch einige Inhalte in einer bestimmten Zelle, die beim Klicken bearbeitbar werden. Ich möchte die Erweiterungsschaltfläche loswerden und die Erweiterung der Zeile durch Doppelklick an einer beliebigen Stelle in der Zeile selbst aktivieren, einschließlich des Felds, das beim Anklicken bearbeitbar wird. Sie können den Ärger hier schon riechen.

Wenn ich auf eine Zeile doppelklicke, werden zuerst zwei Klickereignisse ausgelöst, bevor der Dblclick auftritt. Das heißt, wenn ich auf das Feld doppelklicke, wird es in ein bearbeitbares Feld umgewandelt und die Zeile wird erweitert. Ich möchte das verhindern. Ich möchte, dass der Doppelklick das Auslösen des Einzelklicks verhindert und der Einzelklick wie üblich ausgeführt wird.

Die Verwendung von event.stopPropagation () funktioniert offensichtlich nicht, da es sich um zwei verschiedene Ereignisse handelt.

Irgendwelche Ideen?

Bearbeiten (etwas Semipseudo-Code):

Originalfassung:

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

Gewünschte Version:

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

Prost

39
Swader

Die allgemeine Idee:

  1. Rufen Sie beim ersten Klick nicht die zugehörige Funktion auf (zB single_click_function ()). Stellen Sie stattdessen einen Timer für eine bestimmte Zeit ein (sagen Sie x). Wenn wir in dieser Zeit keinen weiteren Klick erhalten, wählen Sie single_click_function (). Wenn wir eine bekommen, rufen Sie double_click_function () auf.

  2. Der Timer wird gelöscht, sobald der zweite Klick empfangen wird. Es wird auch gelöscht, wenn x Millisekunden abgelaufen sind.

Übrigens, überprüfen Sie die Antwort von Paolo: Sie müssen Click/Mouseup-Ereignisse abbrechen, wenn ein Doppelklick-Event erkannt wird :-)

Bessere Antwort: https://stackoverflow.com/a/7845282/260610

23
UltraInstinct

Arbeitsdemo

$('#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;
});

offensichtlich <td class="dblclickable"> verwenden

12
Popnoodles

Antwort von user822711 zur Wiederverwendung umschreiben:

  $.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);
        }
      }
    })();
  }

Rufen Sie die Funktion auf.

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

Ich habe ein einfaches jQuery-Plugin geschrieben, mit dem Sie ein benutzerdefiniertes "singleclick" -Ereignis verwenden können, um einen Einzelklick von einem Doppelklick zu unterscheiden. Auf diese Weise können Sie eine Schnittstelle erstellen, bei der die Eingabe mit einem einzigen Klick bearbeitet werden kann, während sie durch einen Doppelklick erweitert wird. Ähnlich wie beim Windows/OSX-Dateisystem wird die Benutzeroberfläche umbenannt. 

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...
}
2
omriyariv

Das Problem tritt nur auf, wenn auf das bearbeitbare Feld geklickt wird. Fügen Sie daher einen regulären click -Handler an das Element an, das die Weitergabe des Ereignisses abbricht ( siehe stopPropagation ) und ein Timeout (setTimeout(...)) für beispielsweise 600ms (Die Standardzeit zwischen zwei Klicks, die als Doppelklick gelten sollen, beträgt 500ms [src]). Wenn bis zu diesem Zeitpunkt dblclick noch nicht aufgetreten ist (Sie können in beiden Event-Handlern auf eine Variable zugreifen, die als Flag zum Erkennen dieses Vorgangs dient), können Sie davon ausgehen, dass der Benutzer stattdessen die Zeile erweitern und mit dieser Aktion fortfahren möchte.

IMO, Sie sollten das noch einmal überdenken. Leider kann ein einzelner Klick-Handler nicht wissen, ob der Benutzer dabei ist, einen Doppelklick auszuführen.

Ich schlage vor, beide Aktionen mit einem Klick auszuführen, und verbreiten Sie das bearbeitbare Feld einfach nicht, wenn Sie darauf klicken.

2
James
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));
1
Philippe Perret

Dieses Beispiel in Vanilla-Javascript sollte funktionieren:

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
}
1

Zusätzlich zur Antwort von @puttyshell hat dieser Code Platz für eine visualSingleClick-Funktion. Diese Ausführung läuft vor setTimeout und soll dem Benutzer einige visuelle Aktionen für die Aktion vor dem Timeout anzeigen, und damit kann ich ein größeres Timeout verwenden. Ich verwende dies in einer Google Drive-Browseroberfläche, um dem Benutzer die Datei oder den Ordner anzuzeigen, auf den er geklickt hat. Google Drive selbst macht etwas Ähnliches, hat aber den Code nicht gesehen.

/* 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);
      }
    }
  })();
}
0
chronossc