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


85

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

クリックを許可しながら、そのような要素をドロップしたときにクリックが発生しないようにするための最良の方法は、ドラッグアンドドロップ状態ではありませんか?

並べ替え可能な要素でこの問題が発生しますが、一般的なドラッグアンドドロップの解決策があるとよいと思います。

私は自分で問題を解決しました。その後、Scriptaculousにも同じ解決策が存在することがわかりましたが、おそらく誰かがそれを達成するためのより良い方法を持っています。


回答:


88

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

ドラッグの開始時に、「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
    }
});

1
有用!以前の試みで同じことをいじっていて、クラスがクリックされたものとは異なる要素になってしまったため、一度に機能しませんでした。しかし、とにかく、グローバル変数を使用しました(これは非常に単純なページは大丈夫でした)、そしてそれも非常にうまくいきました。
MSpreij

2
これが私の解決策につながりました。クラスの代わりにjQueryデータ関数を使用しました。ありがとう。
ウィリアム

3
しかし、ブラウザは要素をドロップするたびにクリックイベントをトリガーしません
puchu 2011

6
クラスまたはデータの設定を保存するには、クリックイベントハンドラーで次を使用することもできます:if(!$(this).is( '
。ui

1
おっと、stop: function(event, ui) { $(this).removeClass('noclick'); }ドラッグ可能なハンドラーに入れたくないですか?そうでなければ、すべてのドラッグアンドドロップが「セレクター」の次のクリックを妨げることはありません。
ボブ・スタイン

41

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

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

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

2
これは私にとってクリックイベントを防ぐことができなかったようです、私はjquery1.9.1とjquery.ui1.10.3を使用しています
aaron 2013

1
あなたがあなた自身の質問に答えたのは奇妙で、それも機能していません、サーシャ笑。

@aaron以下のこの回答は機能します: http
lol

別の単純な答え- .draggable()の後だけの場所目jQueryの.click()ハンドラ stackoverflow.com/questions/18032136/...
JxAxMxIxN

1
値 'clone'を指定して属性ヘルパーを渡すと、ドラッグされてソートされたアイテムへのイベントのトリガーが回避されます。{helper: 'clone'、start、stop ... etc}、
Luchux

12

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

解決策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つのケースで失敗します-フルスクリーンのオンクリックを行っていたとき:

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


1
(IE11 / Edgeで)私のために働いたのはソリューション4だけでした。ありがとう!
サイモン

1
#4は、クラスや変数を使用せずに、私にとって正しくて最も単純なソリューションです。
エレクトロタイプ

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 ..


これが私にとって最良の解決策でした。jquery.ui.touch.punch.jsを使用してモバイルWebブラウザーでソート可能なjqueryUIでクリックイベントを機能させるのに問題がありましたが、これによりかなりエレガントに解決されました。
ゴッドスミス2014年

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

2
jquery UIは、ソートされているアイテムに「ui-sortable-helper」クラスを追加しているようです。したがって、「noclick」クラスを省略して、if($(this).hasClass( 'ui-sortable-helper'))を実行することができます。そのようにもっと簡潔に
Matt De Leon

3

デフォルトを妨げずにサーシャの答えの可能な代替案:

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」というクラスが与えられます。
したがって、このクラスを使用して、クリックするかどうかを決定し、イベントを遅らせることができます。
「start」または「stop」コールバック関数を使用する必要はありません。次のようにするだけです。

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

これは、「マウスダウン」や「クリック」ではなく「マウスアップ」からトリガーされるため、わずかな遅延があり、完全ではない可能性がありますが、ここで提案する他のソリューションよりも簡単です。


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

1

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

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

0

event.preventDefault();を使用してリンクを無効にしてみましたか。startイベントで、unbindを使用してdragstoppedイベントまたはdropイベントで再度有効にしますか?


0

上記の答えに追加するためのほんの少しのしわ。SalesForce要素を含むdivをドラッグ可能にする必要がありましたが、SalesForce要素には、VisualForcegobbledigookを介して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

私はこのように試しました:

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

私にとっては、optionsオブジェクトでヘルパーを次のように渡すのに役立ちました。

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

ドラッグされたdom要素のクローンを作成すると、イベントのバブリングが防止されたようです。eventPropagation、バブリングなどでそれを回避することはできませんでした。これが私にとって唯一有効な解決策でした。


0

onmousedownイベントとonmouseupイベントは、私の小さなプロジェクトの1つで機能しました。

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

はい、知っています。最もクリーンな方法ではありませんが、アイデアは得られます。


0

最も簡単で堅牢なソリューション?ドラッグ可能な要素の上に透明な要素を作成するだけです。

.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();
        }
    });
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.