web-dev-qa-db-ja.com

jQueryのドラッグアンドドロップによるクリックイベントの防止

JQueryでドラッグ可能な要素がページにあります。これらの要素には、別のページに移動するクリックイベントがありますか(通常のリンクなど)。

そのような要素のドロップ時にクリックが発生しないようにしながら、クリックやドラッグアンドドロップ状態を許可しない最良の方法は何ですか?

ソート可能な要素にこの問題がありますが、一般的なドラッグアンドドロップの解決策があると良いと思います。

私は自分で問題を解決しました。その後、同じ解決策を見つけました Scriptaculousには存在します ですが、誰かがそれを達成するより良い方法を持っているかもしれません。

82

解決策は、ドラッグの開始時にクリックが伝播しないようにするクリックハンドラを追加することです。そして、ドロップの実行後にそのハンドラーを削除します。クリック防止が機能するためには、最後のアクションを少し遅らせる必要があります。

ソート可能なソリューション:

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

私にとってうまく機能し、タイムアウトを必要としないソリューション:(はい、私は少し面倒です;-)

ドラッグの開始時に、要素にマーカークラスを追加します。 「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
    }
});
88
lex82

私は同じ問題を抱えており、複数のアプローチを試みましたが、どれもうまくいきませんでした。

ソリューション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(); } );
    }
});

これは正常に機能しますが、1つのケースで失敗します。onclickでフルスクリーンにした場合:

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

ソリューション(by 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()イベントにフルスクリーン切り替えコードを配置しても、ドラッグ時にフルスクリーンになりませんでした。私にぴったり!

12
Tom

これに追加したいのは、クリックイベントがドラッグ可能またはソート可能なイベントの後に定義されている場合にのみクリックイベントが防止されるように見えることです。最初にクリックが追加されると、ドラッグ時にアクティブになります。

11
kasakka

私はタイマーを使用したり防止したりするのは本当に好きではないので、私がしたことはこれです:

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

標準のjQueryクリック機能を使用していることがわかりました。

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

jQuery UIでは問題なく動作します。ドラッグアンドドロップ時には、クリックイベントは実行されません。 :)

9
Norm

JQuery UIでは、ドラッグされる要素に「ui-draggable-dragging」クラスが与えられます。
したがって、このクラスを使用して、クリックするかどうかを決定できます。イベントを遅らせるだけです。
「開始」または「停止」コールバック関数を使用する必要はありません。単純に実行してください:

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

これは、「mousedown」または「click」ではなく「mouseup」からトリガーされます。したがって、わずかな遅延があり、完璧ではないかもしれませんが、他のソリューションよりも簡単です。

3
lukesrw

デフォルトを妨げることのないサーシャの答えの代替案:

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

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
orolo

これといくつかのスレッドを読んだ後、これは私が行った解決策でした。

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

私はこのようにしてみました:

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
sun

私の場合、次のように機能しました。

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

Event.preventDefault()を使用してリンクを無効にしようとしましたか?開始イベントで、バインド解除を使用してドラッグ停止イベントまたはドロップイベントで再度有効にしますか?

0
alienonland

上記の回答に追加する少ししわです。 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');
    }
});

親のクリックイベントは、基本的に子要素をダブルクリックする必要を隠し、ユーザーエクスペリエンスをそのまま残します。

0
geekbrit