簡體   English   中英

使用 jQuery 拖放防止單擊事件

[英]Preventing click event with jQuery drag and drop

我在頁面上有可以使用 jQuery 拖動的元素。 這些元素是否具有導航到另一個頁面的點擊事件(例如普通鏈接)。

防止單擊在放置此類元素時觸發同時允許單擊它不是拖放狀態的最佳方法是什么?

我對可排序元素有這個問題,但認為為一般拖放提供解決方案是件好事。

我已經為自己解決了這個問題。 在那之后,我發現Scriptaculous 存在相同的解決方案,但也許有人有更好的方法來實現這一目標。

一個對我來說效果很好並且不需要超時的解決方案:(是的,我有點迂腐;-)

我在拖動開始時向元素添加一個標記類,例如“noclick”。 當元素被放置時,點擊事件被觸發——更准確地說,如果拖動結束,實際上它不必被放置到一個有效的目標上。 在點擊處理程序中,我刪除標記類(如果存在),否則點擊正常處理。

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

解決方案是添加單擊處理程序,以防止單擊在拖動開始時傳播。 然后在執行 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);
        }
...
})

我遇到了同樣的問題並嘗試了多種方法,但沒有一種對我有用。

解決方案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() 事件中,拖動時它仍然沒有進入全屏。 適合我!

我想補充一點,似乎只有在可拖動或可排序事件之后定義點擊事件時,才能阻止點擊事件。 如果首先添加點擊,它會在拖動時激活。

我真的不喜歡使用計時器或預防,所以我所做的是:

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點擊功能:

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

在jQuery UI中運行得很好。 拖放時不會執行click事件。 :)

在不阻止默認值的情況下,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);
        },

在 jQuery UI 中,被拖動的元素被賦予“ui-draggable-dragging”類。
因此我們可以使用這個類來判斷是否點擊,只是延遲事件。
您不需要使用“開始”或“停止”回調函數,只需執行以下操作:

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

這是由“mouseup”觸發的,而不是“mousedown”或“click”——所以有一點延遲,可能並不完美——但它比這里建議的其他解決方案更容易。

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

閱讀完這篇文章和一些線程后,這是我采用的解決方案。

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

在我的情況下,它是這樣工作的:

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

最簡單、最可靠的解決方案? 只需在可拖動對象上創建透明元素即可。

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

只是有點皺紋添加到上面給出的答案。 我必須制作一個包含 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');
    }
});

父元素的點擊事件本質上隱藏了雙擊子元素的需要,讓用戶體驗保持不變。

您是否嘗試過使用 event.preventDefault(); 禁用鏈接? 在開始事件中並使用解除綁定在拖動停止事件或放置事件中重新啟用它?

我試過這樣:

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

});

對我來說,幫助將選項對象中的幫助程序傳遞為:

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

似乎克隆被拖動的 dom 元素阻止了事件的冒泡。 我無法通過任何 eventPropagation、冒泡等來避免它。這是對我來說唯一可行的解​​決方案。

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" ); } }
 <img src=".." onmousedown="startClick();" onmouseup="endClick();" />

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM