【问题标题】:Preventing click event with jQuery drag and drop使用 jQuery 拖放防止单击事件
【发布时间】:2010-12-18 19:15:06
【问题描述】:

我在页面上有可以用 jQuery 拖动的元素。这些元素是否具有导航到另一个页面的点击事件(例如普通链接)。

什么是防止点击在放置此类元素时触发的最佳方法,同时允许点击它不是拖放状态?

我对可排序元素有这个问题,但我认为最好有一个通用拖放的解决方案。

我自己解决了这个问题。之后我找到了相同的解决方案exists for Scriptaculous,但也许有人有更好的方法来实现这一点。

【问题讨论】:

标签: javascript jquery events drag-and-drop jquery-ui-sortable


【解决方案1】:

对我来说效果很好且不需要超时的解决方案:(是的,我有点迂腐;-)

我在拖动开始时向元素添加了一个标记类,例如'无点击'。当元素被放下时,点击事件被触发——更准确地说,如果拖动结束,实际上它不必被放置到一个有效的目标上。在单击处理程序中,如果存在标记类,我将删除,否则单击将正常处理。

$('your selector').draggable({
    start: function(event, ui) {
        $(this).addClass('noclick');
    }
});

$('your selector').click(function(event) {
    if ($(this).hasClass('noclick')) {
        $(this).removeClass('noclick');
    }
    else {
        // actual click event code
    }
});

【讨论】:

  • 有用!一口气没有为我工作,可能是因为我在以前的尝试中搞砸了同一件事,并且类最终在与单击的元素不同的元素上..但无论如何,我使用了一个全局变量(在这个非常简单的页面还可以),而且效果也很好。
  • 这引导我找到我的解决方案,我只是使用了 jQuery 数据函数而不是一个类。谢谢。
  • 但浏览器不会在每次放置元素时触发点击事件
  • 要保存设置类或数据,在单击事件处理程序中,您还可以使用: if (!$(this).is('.ui-draggable-dragging')) { ...点击操作}
  • 糟糕,您不想在可拖动处理程序中使用stop: function(event, ui) { $(this).removeClass('noclick'); } 吗?否则不会每次在其他地方拖放都会阻止下一次点击“您的选择器”。
【解决方案2】:

解决方案是添加单击处理程序,以防止单击在拖动开始时传播。然后在执行 drop 后删除该处理程序。最后一个操作应该延迟一点,以防止点击工作。

可排序的解决方案:

...
.sortable({
...
        start: function(event, ui) {
            ui.item.bind("click.prevent",
                function(event) { event.preventDefault(); });
        },
        stop: function(event, ui) {
            setTimeout(function(){ui.item.unbind("click.prevent");}, 300);
        }
...
})

可拖动的解决方案:

...
.draggable({
...
        start: function(event, ui) {
            ui.helper.bind("click.prevent",
                function(event) { event.preventDefault(); });
        },
        stop: function(event, ui) {
            setTimeout(function(){ui.helper.unbind("click.prevent");}, 300);
        }
...
})

【讨论】:

  • 似乎这无法阻止我的点击事件,我使用 jquery 1.9.1 和 jquery.ui 1.10.3
  • 奇怪的是你回答了你自己的问题,而且它甚至不起作用,萨沙哈哈。
  • @aaron 这个答案在下面有效:http://stackoverflow.com/a/4572831/119765
  • 另一个简单的答案 - 只需将 jQuery .click() 处理程序放在 .draggable() stackoverflow.com/questions/18032136/… 之后
  • 如果你传递值为'clone'的属性助手,它会避免触发事件到拖拽排序的项目.. {helper: 'clone', start, stop...等},
【解决方案3】:

我遇到了同样的问题并尝试了多种方法,但没有一个对我有用。

解决方案 1

$('.item').click(function(e)
{            
    if ( $(this).is('.ui-draggable-dragging') ) return false;
});  

对我没有任何帮助。拖动完成后正在单击该项目。

解决方案 2(作者:Tom de Boer)

$('.item').draggable(
{   
    stop: function(event, ui) 
    {
         $( event.originalEvent.target).one('click', function(e){ e.stopImmediatePropagation(); } );
    }
});

这工作得很好,但在一种情况下失败了——当我要全屏点击时:

var body = $('body')[0];     
req = body.requestFullScreen || body.webkitRequestFullScreen || body.mozRequestFullScreen;
req.call(body); 

解决方案 3(作者 Sasha Yanovets)

 $('.item').draggable({
        start: function(event, ui) {
            ui.helper.bind("click.prevent",
                function(event) { event.preventDefault(); });
        },
        stop: function(event, ui) {
            setTimeout(function(){ui.helper.unbind("click.prevent");}, 300);
        }
})

这对我不起作用。

解决方案 4 - 唯一可以正常工作的解决方案

$('.item').draggable(
{   
});
$('.item').click(function(e)
{  
});

是的,就是这样-正确的顺序可以解决问题-首先您需要绑定 draggable() 然后 click() 事件。即使我将全屏切换代码放在 click() 事件中,拖动时它仍然没有进入全屏。非常适合我!

【讨论】:

  • 解决方案 4 对我有用(在 IE11/Edge 中)。谢谢!
  • #4 对我来说是正确且最简单的解决方案,无需使用类或变量。
【解决方案4】:

我想补充一点,似乎只有在可拖动或可排序事件之后定义单击事件时,才能阻止单击事件。如果首先添加点击,它会在拖动时激活。

【讨论】:

    【解决方案5】:

    我不太喜欢使用计时器或预防,所以我这样做是:

    var el, dragged
    
    el = $( '#some_element' );
    
    el.on( 'mousedown', onMouseDown );
    el.on( 'mouseup', onMouseUp );
    el.draggable( { start: onStartDrag } );
    
    onMouseDown = function( ) {
      dragged = false;
    }
    
    onMouseUp = function( ) {
      if( !dragged ) {
        console.log('no drag, normal click')
      }
    }
    
    onStartDrag = function( ) {
      dragged = true;
    }
    

    坚如磐石..

    【讨论】:

    • 这对我来说是最好的解决方案。我在使用 jquery.ui.touch.punch.js 在移动网络浏览器中对可排序的 jquery UI 进行点击事件时遇到了麻烦,但这相当优雅地解决了它。
    【解决方案6】:

    lex82 的版本,但用于 .sortable()

     start: function(event, ui){
     ui.item.find('.ui-widget-header').addClass('noclick');
     },
    

    你可能只需要:

     start: function(event, ui){
     ui.item.addClass('noclick');
     },
    

    这是我用于切换的:

    $("#datasign-widgets .ui-widget-header").click(function(){
    if ($(this).hasClass('noclick')) {
    $(this).removeClass('noclick');
    
    }
    else {
    $(this).next().slideToggle();
    $(this).find('.ui-icon').toggleClass("ui-icon-minusthick").toggleClass("ui-icon-plusthick");
    }
    });
    

    【讨论】:

    • 似乎 jquery UI 将 'ui-sortable-helper' 类附加到正在排序的项目。所以,你可以省略“noclick”类,只做 if ($(this).hasClass('ui-sortable-helper'))。那样更简洁
    【解决方案7】:

    Sasha 的答案的一种可能的替代方案,而不会阻止默认:

    var tmp_handler;
    .sortable({
            start : function(event,ui){
                tmp_handler = ui.item.data("events").click[0].handler;
                ui.item.off();
            },
            stop : function(event,ui){
                setTimeout(function(){ui.item.on("click", tmp_handler)}, 300);
            },
    

    【讨论】:

      【解决方案8】:

      在 jQuery UI 中,被拖动的元素被赋予“ui-draggable-dragging”类。
      因此我们可以使用这个类来判断是否点击,只是延迟事件。
      您不需要使用“开始”或“停止”回调函数,只需这样做:

      $('#foo').on('mouseup', function () {
          if (! $(this).hasClass('ui-draggable-dragging')) {
              // your click function
          }
      });
      

      这是由“mouseup”触发的,而不是“mousedown”或“click” - 所以会有一点延迟,可能并不完美 - 但它比这里建议的其他解决方案更容易。

      【讨论】:

        【解决方案9】:

        就我而言,它是这样工作的:

        $('#draggable').draggable({
          start: function(event, ui) {
            $(event.toElement).one('click', function(e) { e.stopPropagation(); });
          }
        });
        

        【讨论】:

          【解决方案10】:

          在阅读了这个和几个线程之后,这是我采用的解决方案。

          var dragging = false;
          $("#sortable").mouseover(function() {
              $(this).parent().sortable({
                  start: function(event, ui) {
                      dragging = true;
                  },
                  stop: function(event, ui) {
                      // Update Code here
                  }
              })
          });
          $("#sortable").click(function(mouseEvent){
              if (!dragging) {
                  alert($(this).attr("id"));
              } else {
                  dragging = false;
              }
          });
          

          【讨论】:

            【解决方案11】:

            最简单、最可靠的解决方案?只需在您的可拖动元素上创建透明元素。

            .click-passthrough {
              position: absolute;
              left: 0;
              top: 0;
              right: 0;
              bottom: 0;
              background: transparent;
            }
            
            element.draggable({        
                    start: function () {
            
                    },
                    drag: function(event, ui) {
                        // important! if create the 'cover' in start, then you will not see click events at all
                              if (!element.find('.click-passthrough').length) {
                                  element.append("<div class='click-passthrough'></div>");
                              }
                    },
                    stop: function() {
                      // remove the cover
                      element.find('.click-passthrough').remove();
                    }
                });
            

            【讨论】:

              【解决方案12】:

              您是否尝试过使用 event.preventDefault(); 禁用链接?在 start 事件中并在拖动停止事件或 drop 事件中使用 unbind 重新启用它?

              【讨论】:

                【解决方案13】:

                在上面给出的答案中添加一点皱纹。我必须制作一个包含可拖动 SalesForce 元素的 div,但 SalesForce 元素通过一些 VisualForce gobbledigook 在 html 中定义了一个 onclick 操作。

                显然这违反了“在拖动操作之后定义单击操作”规则,因此作为一种解决方法,我重新定义了要触发“onDblClick”的 SalesForce 元素的操作,并将此代码用于容器 div:

                $(this).draggable({
                        zIndex: 999,
                        revert: true,
                        revertDuration: 0,
                        start: function(event, ui) {
                                   $(this).addClass('noclick');
                                }
                });
                
                $(this).click(function(){
                    if( $(this).hasClass('noclick'))
                    {
                        $(this).removeClass('noclick');
                    }
                    else
                    {
                        $(this).children(":first").trigger('dblclick');
                    }
                });
                

                父元素的点击事件本质上隐藏了双击子元素的需要,保持用户体验不变。

                【讨论】:

                  【解决方案14】:

                  我试过这样:

                  var dragging = true; 
                  
                  $(this).click(function(){
                    if(!dragging){
                      do str...
                    }
                  });
                  
                  $(this).draggable({
                    start: function(event, ui) {
                        dragging = true;
                    },
                  
                    stop: function(event, ui) {
                        setTimeout(function(){dragging = false;}, 300);
                    }
                  
                  });
                  

                  【讨论】:

                    【解决方案15】:

                    对我来说,帮助将选项对象中的助手传递为:

                    .sortable({
                       helper : 'clone', 
                       start:function(), 
                       stop:function(),
                       .....
                    });
                    

                    似乎克隆被拖动的 dom 元素阻止了事件的冒泡。我无法通过任何 eventPropagation、冒泡等来避免它。这对我来说是唯一可行的解​​决方案。

                    【讨论】:

                      【解决方案16】:

                      onmousedown 和 onmouseup 事件在我的一个较小的项目中起作用。

                      var mousePos = [0,0];
                      function startClick()
                      {
                          mousePos = [event.clientX,event.clientY];
                      }
                              
                      function endClick()
                      {
                          if ( event.clientX != mousePos[0] && event.clientY != mousePos[1] )
                          {
                              alert( "DRAG CLICK" );
                          }
                          else
                          {
                              alert( "CLICK" );
                          }
                      }
                      &lt;img src=".." onmousedown="startClick();" onmouseup="endClick();" /&gt;

                      是的,我知道。不是最干净的方法,但你明白了。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2010-09-21
                        • 2013-08-04
                        • 1970-01-01
                        • 1970-01-01
                        • 2012-01-17
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多