【问题标题】:Javascript with jQuery: Click and double click on same element, different effect, one disables the other带有jQuery的Javascript:单击并双击相同的元素,不同的效果,一个禁用另一个
【发布时间】:2011-07-25 04:26:32
【问题描述】:

我有一个有趣的情况 - 我有一个表格行,当前,当我单击“展开”按钮时,它显示它是隐藏的对应项。包含展开按钮的原始(未隐藏)行在某个单元格中也有一些内容,当单击这些内容时,这些内容变为可编辑的。我想摆脱展开按钮,并通过双击行本身的任何位置来扩展行,包括单击它时变为可编辑的字段。你已经可以闻到这里的麻烦了。

当我双击一行时,在 dblclick 发生之前首先触发两个单击事件。这意味着如果我双击该字段,它将变成一个可编辑的字段,并且该行将展开。我想防止这种情况。我希望双击以防止触发单击,并像往常一样执行单击。

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

干杯

【问题讨论】:

  • 您可以尝试使用 setTimeout 延迟点击处理程序,然后在双击时引发“doubleclick-has-happened”标志,并在单击处理程序中检查该标志
  • @diEcho 完成! @freaktm 谢谢,我考虑过这一点,但它似乎不切实际和骇人听闻,特别是因为我必须修改我的可编辑单元格助手站点范围内的点击处理程序。我可能会将此作为最后的手段,是的,但仍然想知道是否有人有更好的解决方案。
  • 如果你到了那里,我已经为你做了一个例子:jsfiddle.net/nslr/2TvgE 但是是的,不是很漂亮:)
  • 嗯,试过了,好像没有按计划工作。当我双击时,我得到双击,当我单击时,我得到单击。但是当我双击后双击时,我得到了单击和双击:)

标签: javascript jquery events event-bubbling propagation


【解决方案1】:

总体思路:

  1. 在第一次单击时,不要调用关联的函数(例如 single_click_function())。相反,设置一个特定时间段的计时器(比如 x)。如果在这段时间内我们没有再次点击,请使用 single_click_function()。如果我们确实得到了一个,请调用 double_click_function()

  2. 一旦收到第二次点击,计时器将被清除。一旦经过 x 毫秒,它也会被清除。

顺便说一句,请查看 Paolo 的回复:Need to cancel click/mouseup events when double-click event detected 当然还有整个线程! :-)

更好的答案:https://stackoverflow.com/a/7845282/260610

【讨论】:

  • 谢谢,这行得通,但我最终决定不这样做。我找到了一些更好的可用性解决方案并采用了这些解决方案。
  • @Swader 你能分享你的解决方案吗?你选择 b/c 的解决方法我也不想使用 settimeout(...) 方法。
  • @Swader 正在拉费马
  • 我猜这个家伙从来没有发布过更好的解决方案...?
  • @BrianStinar 我会的——如果 OP 发布了他解决问题的 Javascript 尝试。 HTML 伪结构或冗长的解释不算在内。
【解决方案2】:

Working demo

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

显然使用&lt;td class="dblclickable"&gt;

【讨论】:

  • 我把它调到 1300,不管我点击多快,它都会将我显示“单人”的警报延迟一秒钟。
  • 实际上,如果我慢慢点击,我可以让 dbl 在 1300 窗口中触发。单击 1 = 0,单击 2 = 500 毫秒后(-ish)时间范围。 2 次缓慢的刻意点击。是通过 JS 文件所需的时间(函数(){}包装器中的一堆东西导致等待加载?
  • 不,我的逻辑是正确的jsfiddle.net/V8twU你把你的双击事件的程序放在正确的地方了吗?
  • 你在ie8中试过了吗?即使对我来说,它似乎也无法正确触发。
  • 嘿,我很乐意。不幸的是,这就是这里的“环境”,它是唯一仍在使用的浏览器。 :(
【解决方案3】:

我编写了一个简单的 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...
}

【讨论】:

    【解决方案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){
      //single click.
    }, function(e){
      //double click.
    }));
    

    【讨论】:

    • 我似乎无法让它工作...在函数调用中不断出现 ) 缺失错误。
    【解决方案5】:

    该问题仅在单击可编辑字段时出现,因此将常规 click 处理程序附加到该元素,这将取消事件的传播 (see stopPropagation) 并设置超时 (setTimeout(...)),例如, 600 毫秒(两次点击之间被视为 dbl-click 的默认时间为 500 毫秒 [src])。如果到那时dblclick 还没有发生(您可以在两个事件处理程序中都有一个可访问的变量作为一个标志来检测这一点),那么您可以假设用户想要展开该行并继续该操作。 ..

    IMO,您应该重新考虑这一点。唉,单击处理程序无法知道用户是否要双击。

    我建议让这两个动作都单击一次,并且在单击时不要从可编辑字段向上传播。

    【讨论】:

      【解决方案6】:

      原版 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
      }
      

      【讨论】:

        【解决方案7】:
        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));
        

        【讨论】:

          【解决方案8】:

          为了回答@puttyshell,这段代码有空间用于visualSingleClick 函数。这在setTimeout 之前运行,旨在向用户显示超时前该操作的一些视觉操作,这样我就可以使用更大的超时时间。我在 Google Drive 浏览界面上使用它来向用户显示他单击的文件或文件夹已被选中。 Google Drive 本身也有类似的功能,但没有看到它的代码。

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

          【讨论】:

            【解决方案9】:

            如果您使用的是backbonejs,有一种更优雅的方式来处理这个问题:

            初始化:函数(){ this.addListener_openWidget(); } addListener_openWidget:函数(){ this.listenToOnce( this, 'openWidgetView', function(e){this.openWidget(e)} ); }, 事件:{ '点击#openWidgetLink' : function(e){this.trigger('openWidgetView',e)}, '点击#closeWidgetLink' : 'closeWidget' }, openWidget:函数(e){ //做你的事 }, 关闭小部件:函数(){ this.addListener_openWidget(); }

            【讨论】:

              猜你喜欢
              • 2012-04-14
              • 2017-09-09
              • 1970-01-01
              • 2016-04-06
              • 1970-01-01
              • 2019-10-25
              • 2010-11-21
              • 2015-01-18
              • 1970-01-01
              相关资源
              最近更新 更多