JQuery sürükle ve bırak ile tıklama olayını önleme


86

Sayfada jQuery ile sürüklenebilen öğelerim var. Bu öğelerin başka bir sayfaya giden tıklama olayları var mı (örneğin, sıradan bağlantılar).

Tıklamanın sürüklenip bırakılmamasına izin verirken, bu tür bir öğeyi bıraktığında tıklamanın etkin olmasını önlemenin en iyi yolu nedir?

Sıralanabilir öğelerle ilgili bu sorunu yaşıyorum, ancak genel sürükle ve bırak için bir çözüme sahip olmanın iyi olduğunu düşünüyorum.

Sorunu kendim çözdüm. Bundan sonra Scriptaculous için de aynı çözümün var olduğunu buldum , ancak belki birinin bunu başarmak için daha iyi bir yolu vardır.


Yanıtlar:


89

Benim için iyi çalışan ve zaman aşımı gerektirmeyen bir çözüm: (evet biraz bilgiçim ;-)

Sürükleme başladığında öğeye bir işaret sınıfı eklerim, örneğin 'noclick'. Öğe bırakıldığında, tıklama olayı tetiklenir - daha kesin olarak, sürükleme biterse, aslında geçerli bir hedefe bırakılması gerekmez. Tıklama işleyicisinde, varsa işaretçi sınıfını kaldırırım, aksi takdirde tıklama normal şekilde işlenir.

$('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
Kullanışlı! Benim için tek seferde çalışmadı, muhtemelen önceki denemelerde aynı şeyi karıştırdığım için ve sınıflar tıklanandan farklı bir öğe ile sonuçlandı .. ama yine de, global bir değişken kullandım (bu son derece basit sayfa iyiydi) ve bu da oldukça iyi çalıştı.
MSpreij

2
Bu beni çözümüme götürdü, sadece bir sınıf yerine jQuery veri işlevini kullandım. Teşekkürler.
William

3
ancak öğeyi her bıraktığınızda tarayıcı tıklama olayını tetiklemeyecek
puchu

6
Bir sınıf veya veri ayarını kaydetmek için, tıklama olay işleyicisinde şunları da kullanabilirsiniz: if (! $ (This) .is ('.
Ui

1
Oops, stop: function(event, ui) { $(this).removeClass('noclick'); }sürüklenebilir işleyicide istemiyor musunuz? Aksi takdirde, başka bir yerdeki her sürükle-bırak işlemi, 'seçiciniz'e bir sonraki tıklamayı engellemez.
Bob Stein

41

Çözüm, sürüklemenin başlangıcında tıklamanın yayılmasını önleyecek tıklama işleyicisi eklemektir. Ve düşme gerçekleştirildikten sonra bu işleyiciyi kaldırın. Tıklama engellemenin çalışması için son işlem biraz gecikmeli olmalıdır.

Sıralanabilir çözüm:

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

Sürüklenebilir çözüm:

...
.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
bu benim için tıklama olayını engelleyemiyor gibi görünüyor, jquery 1.9.1 ve jquery.ui 1.10.3 kullanıyorum
aaron

1
Kendi sorunuzu yanıtlamanız garip ve işe yaramıyor bile, Sasha lol.

@aaron aşağıdaki yanıt işe yarar: http://stackoverflow.com/a/4572831/119765
lol

Başka bir basit cevap - jQuery .click () işleyicisini .draggable () stackoverflow.com/questions/18032136/…
JxAxMxIxN

1
'clone' değerine sahip öznitelik yardımcısını iletirseniz, olayın sürüklenen sıralı öğeye tetiklenmesini önler .. {helper: 'clone', start, stop ... etc},
Luchux

12

Aynı sorunu yaşadım ve birden fazla yaklaşım denedim ve hiçbiri benim için işe yaramadı.

1.Çözüm

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

benim için hiçbir şey yapmaz. Sürükleme tamamlandıktan sonra öğe tıklanıyor.

Çözüm 2 (Tom de Boer tarafından)

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

Bu gayet iyi çalışıyor ancak bir durumda başarısız oluyor - tam ekrana geçerken onclick:

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

Çözüm 3 (Sasha Yanovets tarafından)

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

Bu benim için çalışmıyor.

Çözüm 4- İyi çalışan tek çözüm

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

Evet, işte bu - doğru sıra hile yapar - önce sürüklenebilir () bağlamanız ve ardından () olayına tıklamanız gerekir. Click () olayına tam ekran geçiş kodunu koysam bile, sürüklerken hala tam ekrana geçmedi. Benim için mükemmel!


1
Benim için çalışan tek bir çözüm (IE11 / Edge'de) 4. çözümdü. Teşekkürler!
Simon

1
# 4, sınıfları veya değişkenleri kullanmadan benim için doğru ve en basit çözümdür.
elektrotip

11

Buna, tıklama olayını engellemenin, yalnızca tıklama olayı sürüklenebilir veya sıralanabilir olaydan SONRA tanımlanırsa işe yarayacağını eklemek isterim. Önce tıklama eklenirse, sürüklemeyle etkinleştirilir.


9

Zamanlayıcı kullanmayı veya engellemeyi gerçekten sevmiyorum, bu yüzden yaptığım şey şuydu:

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


Bu benim için en iyi çözümdü. Tıklama etkinliklerini, jquery.ui.touch.punch.js kullanarak bir mobil web tarayıcısında sıralanabilen bir jquery kullanıcı arayüzünde çalıştırırken sorun yaşadım, ancak bu sorunu oldukça zarif bir şekilde çözdü.
Godsmith

3

lex82 sürümü ancak .sortable () içindir

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

ve yalnızca şunlara ihtiyacınız olabilir:

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

ve işte geçiş için kullandığım şey:

$("#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
Görünüşe göre jquery UI, sıralanan öğeye 'ui-sortable-helper' sınıfını ekler. Yani, 'noclick' sınıfını dışarıda bırakabilir ve sadece if ($ (this) .hasClass ('ui-sortable-helper')) yapabilirsiniz. Bu şekilde daha kısa
Matt De Leon

3

Varsayılanı engellemeden Sasha'nın cevabı için olası bir alternatif:

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 kullanıcı arayüzünde, sürüklenen öğelere "ui-draggable-dragging" sınıfı verilir.
Bu nedenle, bu sınıfı tıklayıp tıklamayacağımızı belirlemek için kullanabiliriz, sadece etkinliği geciktirebiliriz.
"Başlat" veya "durdur" geri çağırma işlevlerini kullanmanız gerekmez, şunları yapmanız yeterlidir:

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

Bu, "fare kaldırma" veya "tıklama" yerine "fareyi kaldırma" ile tetiklenir - bu nedenle hafif bir gecikme olabilir, mükemmel olmayabilir - ancak burada önerilen diğer çözümlerden daha kolaydır.


1

Bunu ve birkaç konuyu okuduktan sonra, benim kullandığım çözüm buydu.

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

Benim durumumda şu şekilde çalıştı:

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

0

Event.preventDefault () kullanarak bağlantıyı devre dışı bırakmayı denediniz mi; başlatma olayında ve sürüklemeyi durdurma olayında veya unbind kullanarak bırak olayında yeniden etkinleştirme?


0

Yukarıda verilen cevaplara eklemek için biraz kırışıklık. Sürüklenebilir bir SalesForce öğesi içeren bir div yapmak zorunda kaldım, ancak SalesForce öğesi, bazı VisualForce gobbledigook aracılığıyla html'de tanımlanan bir onclick eylemine sahip.

Açıkçası bu, "sürükleme işleminden sonra tıklama eylemini tanımla" kuralını ihlal ediyor, dolayısıyla geçici bir çözüm olarak SalesForce öğesinin "onDblClick" tetiklenmesini yeniden tanımladım ve bu kodu kapsayıcı div için kullandım:

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

Üst öğenin tıklama olayı temelde alt öğeye çift tıklama ihtiyacını gizleyerek kullanıcı deneyimini olduğu gibi bırakır.


0

Ben böyle denedim:

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

benim için yardımcının options nesnesinde şu şekilde geçmesine yardımcı oldu:

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

Görünüşe göre sürüklenen dom öğesi klonlama, olayın köpürmesini engelliyor. Herhangi bir eventPropagation, fokurdama vb. İle bundan kaçınamadım. Bu benim için çalışan tek çözümdü.


0

Onmousedown ve onmouseup etkinlikleri daha küçük projelerimden birinde işe yaradı.

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

Evet biliyorum. En temiz yol değil ama fikri anladınız.


0

en kolay ve sağlam çözüm? sadece sürüklenebilir cihazınızın üzerinde şeffaf bir öğe oluşturun.

.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();
        }
    });
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.