通过jQuery拖放防止点击事件

问题描述 投票:83回答:15

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

防止在单击时拖放该元素同时允许其不处于拖放状态的最佳方法是什么?

我对可排序元素有这个问题,但是认为有一种通用拖放方法是很好的。

我已经为自己解决了这个问题。之后,我发现了相同的解决方案exists for Scriptaculous,但也许有人有更好的方法来实现这一目标。

javascript jquery events drag-and-drop jquery-ui-sortable
15个回答
88
投票

一种对我来说很好的解决方案,不需要超时:(是的,我有点书呆子;-)

例如,开始拖动时,我会向元素添加标记类。 'noclick'。放下元素后,将触发click事件-更精确地说,如果拖动结束,则实际上不必将其放到有效目标上。在点击处理程序中,如果存在标记,则删除标记类,否则将正常处理点击。

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

1
投票

阅读完本章和一些线程之后,这就是我所采用的解决方案。

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;
    }
});

0
投票

您是否尝试使用event.preventDefault()禁用链接;在开始事件中,然后使用取消绑定在拖动停止事件或放置事件中重新启用它?


0
投票

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

显然,这违反了“拖动动作后定义点击动作”规则,因此,作为一种解决方法,我将SalesForce元素的动作重新定义为触发“ onDblClick”,并将此代码用于容器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');
    }
});

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


0
投票

我尝试过这样:

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);
  }

});

0
投票

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

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

0
投票

对我来说,将帮助器作为选项传递给了对象:

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

似乎可以拖动克隆dom元素来防止事件冒泡。我无法通过任何eventPropagation,冒泡等方式来避免这种情况。这是我唯一可行的解​​决方案。


38
投票

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

可排序解决方案:

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

12
投票

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

解决方案1

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

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

解决方案2(作者汤姆·德布尔)

$('.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()事件中,拖动时仍无法全屏显示。最适合我!


11
投票

我想补充一点,似乎只有在可拖动事件或可排序事件之后定义了单击事件的情况下,防止单击事件才会起作用。如果单击首先添加,则在拖动时将被激活。


9
投票

我不是很喜欢使用计时器或阻止计时器,所以我这样做是:

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

Rocksolid ..


9
投票

我发现使用标准的jQuery单击功能:

$("#element").click(function(mouseEvent){ // click event });

在jQuery UI中工作正常。拖放时将不执行click事件。 :)


3
投票

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");
}
});

3
投票

[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);
        },

3
投票

在jQuery UI中,被拖动的元素被赋予类“ ui-draggable-dragging”。因此,我们可以使用此类来确定是否单击,只是延迟事件。您无需使用“开始”或“停止”回调函数,只需执行以下操作:

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

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

© www.soinside.com 2019 - 2024. All rights reserved.