Üst öğenin 'dragleave', alt öğelerin üzerine sürüklenirken tetiklenir


163

genel bakış

Aşağıdaki HTML yapısı var ve öğeye dragenterve dragleaveolayları <div id="dropzone">ekledim.

<div id="dropzone">
    <div id="dropzone-content">
        <div id="drag-n-drop">
            <div class="text">this is some text</div>
            <div class="text">this is a container with text and images</div>
        </div>
    </div>
</div>

Sorun

Bir dosyayı üzerine sürüklediğimde <div id="dropzone">, dragenterolay beklendiği gibi tetiklenir. Ancak, faremi bir öğe üzerinde gezdirdiğimde, öğe <div id="drag-n-drop">için dragenterolay tetiklenir <div id="drag-n-drop">ve sonra öğe için dragleaveolay tetiklenir <div id="dropzone">.

<div id="dropzone">Tekrar öğenin üzerine gelirseniz , dragenterolay tekrar tetiklenir, bu da serindir, ancak daha sonra dragleaveolay, alt öğe için bırakılır, bu nedenle removeClasstalimat, yürütülür, bu da serin değildir.

Bu davranış 2 nedenden dolayı sorunludur:

  1. Sadece ekliyorum dragenterve dragleavebu <div id="dropzone">yüzden çocuk öğelerinin neden bu olaylara bağlı olduğunu anlamıyorum.

  2. Hala <div id="dropzone">çocuklarının üzerine gelirken elemanın üzerine sürüklüyorum, bu yüzden dragleaveateş etmek istemiyorum !

jsFiddle

İşte şaka yapmak için bir jsFiddle: http://jsfiddle.net/yYF3S/2/

Soru

Öyleyse ... bir <div id="dropzone">öğeyi öğenin dragleaveüzerine sürüklediğimde, herhangi bir alt öğenin üzerine sürüklesem bile ateşlemeyecek şekilde nasıl yapabilirim ... sadece <div id="dropzone">öğeyi terk ettiğimde ateşlenmelidir .. . gezinip / elemanın sınırları içinde herhangi bir yerde etrafında sürükleyerek olmamalı tetikleyecek dragleaveolayı.

En azından HTML5 sürükle-bırak özelliğini destekleyen tarayıcılarda çapraz tarayıcı uyumlu olması gerekiyor, bu yüzden bu cevap yeterli değil.

Google ve Dropbox bunu çözmüş gibi görünüyor, ancak kaynak kodları küçültülmüş / karmaşık olduğundan, uygulamalarından anlayamadım.


Olayın yayılmasını önleyine.stopPropagation();
Blender

Sanırım ben zaten ... güncellemeyi kontrol et
Hristo

Jsfiddle.net insanlar bir yerde bir demo gönderebilir miyim insanlar onunla tamircilik olabilir?
Blender

@Blender ... emin olun, bana birkaç dakika ver!
Hristo

@Blender ... Sorumumu bir kemanla güncelledim
Hristo

Yanıtlar:


171

Olayları alt öğelere bağlamanız gerekmiyorsa, her zaman pointer-events özelliğini kullanabilirsiniz.

.child-elements {
  pointer-events: none;
}

4
En iyi çözüm! Sorunu css kullanarak bu kadar zarif bir şekilde çözebileceğimi bile düşünmemiştim. Çok teşekkür ederim!
serg66

1
Ah evet. Budur!
mcmlxxxiii

23
Bu yaklaşımın tek dezavantajı, alt öğelerdeki tüm işaretçi olaylarını nükte etmesidir (örneğin artık ayrı :hoverstillere veya tıklama olayı işleyicilerine sahip olamazlar ). Bu olayları korumak istiyorsanız, işte kullandığım başka bir çözüm var: bensmithett.github.io/dragster
Ben

2
Dropzone'unuzun tüm çocuklarına ulaşmak için css çocuk seçici ile birleştirin: .dropzone * {pointer-events: none;}
Philipp F

7
Zaten jQuery kullanıyorsunuz, sadece $('.element').addClass('dragging-over')sürüklediğiniz öğeye ve $('.element').removeClass('dragging-over')sürüklediğinizde. Sonra CSS'nizde olabilir .element.dragging-over * { pointer-events: none; }. Bu, yalnızca sürüklediğinizde işaretçi olaylarını tüm alt öğelerden kaldırır.
Gavin

56

Sonunda mutlu olduğum bir çözüm buldum. Aslında istediğimi yapmanın birkaç yolunu buldum ama hiçbiri şu anki çözüm kadar başarılı değildi ... bir çözümde, #dropzoneöğeye bir kenarlık eklemek / kaldırmak için sık sık titreme yaşadım ... başka bir kenarda tarayıcıdan uzaklaşırsanız hiçbir zaman kaldırılmadı.

Neyse, benim en iyi hacky çözüm şudur:

var dragging = 0;

attachEvent(window, 'dragenter', function(event) {

    dragging++;
    $(dropzone).addClass('drag-n-drop-hover');

    event.stopPropagation();
    event.preventDefault();
    return false;
});

attachEvent(window, 'dragover', function(event) {

    $(dropzone).addClass('drag-n-drop-hover');

    event.stopPropagation();
    event.preventDefault();
    return false;
});

attachEvent(window, 'dragleave', function(event) {

    dragging--;
    if (dragging === 0) {
        $(dropzone).removeClass('drag-n-drop-hover');
    }

    event.stopPropagation();
    event.preventDefault();
    return false;
});

Bu oldukça iyi çalışıyor ama Firefox'ta sorunlar ortaya çıktı çünkü Firefox çift davetliydi, dragenterbu yüzden sayacım kapalıydı. Ama yine de, çok zarif bir çözüm değil.

Sonra bu soru üzerine tökezledi: Pencerenin dışına sürüklerken Firefox'ta dragleave olayı nasıl algılanır

Bu yüzden cevabı aldım ve durumuma uyguladım:

$.fn.dndhover = function(options) {

    return this.each(function() {

        var self = $(this);
        var collection = $();

        self.on('dragenter', function(event) {
            if (collection.size() === 0) {
                self.trigger('dndHoverStart');
            }
            collection = collection.add(event.target);
        });

        self.on('dragleave', function(event) {
            /*
             * Firefox 3.6 fires the dragleave event on the previous element
             * before firing dragenter on the next one so we introduce a delay
             */
            setTimeout(function() {
                collection = collection.not(event.target);
                if (collection.size() === 0) {
                    self.trigger('dndHoverEnd');
                }
            }, 1);
        });
    });
};

$('#dropzone').dndhover().on({
    'dndHoverStart': function(event) {

        $('#dropzone').addClass('drag-n-drop-hover');

        event.stopPropagation();
        event.preventDefault();
        return false;
    },
    'dndHoverEnd': function(event) {

        $('#dropzone').removeClass('drag-n-drop-hover');

        event.stopPropagation();
        event.preventDefault();
        return false;
    }
});

Bu temiz ve zarif ve şimdiye kadar test ettiğim her tarayıcıda çalışıyor gibi görünüyor (henüz IE test etmedim).


Şimdiye kadar en iyi çözüm budur.Tek sorun, bir dosya eklediğinizde, kaldırdığınızda ve üzerine başka bir dosya sürüklediğinizde bu kodun çalışmadığıdır. Ancak HoverEnd'i yükselttikten ve HoverStart'ı tekrar yükselttikten sonra bu kod tekrar çalışır.
MysticEarth

@MysticEarth, çalışmadığında demo için bir jsFiddle oluşturabilir misiniz?
Hristo

1
Cevabınız için teşekkür ederim. HTML5 sürükle ve bırak arayüzü ve olay dinleyicileri gerçekten acı verici olabileceğinden bu gerçekten yardımcı oldu. Çılgın olaylarla başa çıkmanın en iyi yolu, özellikle bırakma bölgesi öğelerinin birden fazla örneğini işlemek istediğinizde.
Nico O

Neden stopPropagation () preventDefault () öğesini çağırmalı ve false döndürmeliyiz. Yanlış dönüş yeterli olmalıdır. Olmalı mı?
Dejo

Gereksiz, ama çağırıyor stopPropagation()ve preventDefault()tercih ediliyor. Düşürürdüm return false.
Peeja

38

Bu biraz çirkin ama lanet olsun! ...

'Dragenter' işleyicinizde event.target'ı (kapatmanızın içindeki bir değişkende veya herhangi bir şekilde) saklayın, ardından 'dragleave' işleyicinizde kodunuzu yalnızca event.target === sakladığınız kodla çalıştırın.

'Dragenter'ınız istemediğiniz zaman (yani alt öğelerden ayrıldıktan sonra girerken) ateş ediyorsa, fare üst öğeden ayrılmadan önce en son tetiklendiğinde, üst öğede olur, bu nedenle üst öğe her zaman amaçlanan 'dragleave' öncesi son 'dragenter'.

(function () {

    var droppable = $('#droppable'),
        lastenter;

    droppable.on("dragenter", function (event) {
        lastenter = event.target;
        droppable.addClass("drag-over");            
    });

    droppable.on("dragleave", function (event) {
        if (lastenter === event.target) {
            droppable.removeClass("drag-over");
        }
    });

}());

Bunu daha sonra deneyeceğim. Bir şey varsa, benim çözümümden daha temiz görünüyor, ancak çapraz tarayıcı uyumlu olup olmadığından emin olamıyorum. Bunu nerede test ettiniz?
Hristo

1
yalnızca Chrome'dur ve yalnızca alt öğeler ve kap arasında fiziksel bir boşluk olduğu varsayımı üzerinde çalışabilir.
hacklikecrack

5
Burada en sevdiğim cevap. Hiç çirkin hissetmiyorum :)
Matt Way

1
IE, Chrome, FF'de benim için çalışıyor
Vicentiu Bacioiu

1
Sürükleme çocuklarda başlarsa bu çalışmaz. Örneğin, başka bir pencereden bir şeyin sürükleneceği şekilde sürüklenmesi çocuğun içinde başlar.
FINDarkside

29

İlk başta, bu pointer-events: noneyaklaşımı reddeden millet ile anlaştım . Ama sonra kendime sordum:

Sürükleme işlemi devam ederken alt öğeler üzerinde çalışmak için gerçekten işaretçi etkinliklere ihtiyacınız var mı?

Benim durumumda, ben sürü vb inline-düzenleme ek işlemler için düğmeler göstermek için örn vurgulu, çocuklarda oluyor var ... Ancak, hiçbiri bunun gerekli ve hatta istenen aslında sırasında bir sürükle.

Benim durumumda, işaretçi olaylarını üst kabın tüm alt düğümleri için seçici olarak kapatmak için böyle bir şey kullanıyorum:

  div.drag-target-parent-container.dragging-in-progress * {
    pointer-events: none;
  }

/ Eklemek sınıfını kaldırmak için favori yaklaşımı kullanın dragging-in-progressiçinde dragEnter/ dragLeavebenim yaptığım gibi, olay işleyicileri veya aynı in yapmak dragStart, et. ark.


1
Bu çözüm hem en basit hem de (anlatabildiğim kadarıyla) tam kanıttır. Sınıfı dragstartetkinliğe ekleyin ve kaldırın dragend.
cmann

Bu oldukça güzel bir çözüm ama mükemmel değil. Sürükleme alt öğede başlarsa (başka bir pencereden sürükleme), dragEnter hiçbir zaman tetiklenmez. Ayrıca fareyi, çocuğa geçtiğinizde dragEnter'ın tetiklenmeyeceği kadar hızlı hareket ettirmek de mümkündür, ancak bundan% 100 emin değilsiniz.
FINDarkside

12

Bu bir Chrome hatası gibi görünüyor.

Düşünebildiğim tek çözüm, etkinliklerinizi yakalamak için şeffaf bir yer paylaşımı öğesi oluşturmaktı: http://jsfiddle.net/yYF3S/10/

JS :

$(document).ready(function() {
    var dropzone = $('#overlay');

    dropzone.on('dragenter', function(event) {
        $('#dropzone-highlight').addClass('dnd-hover');
    });

    dropzone.on('dragleave', function(event) {
        $('#dropzone-highlight').removeClass('dnd-hover');
    });

});​

HTML :

<div id="dropzone-highlight">
    <div id="overlay"></div>

    <div id="dropzone" class="zone">
        <div id="drag-n-drop">
            <div class="text1">this is some text</div>
            <div class="text2">this is a container with text and images</div>
        </div>
    </div>
</div>

<h2 draggable="true">Drag me</h2>

cevap için teşekkürler Blender. Ancak bunu zaten denedim. Bu çözümün sorunu, bindirme öğesinin etkileşime girmem gereken çocuk öğelerini "bindirmesi" ... böylece bir bindirmeye sahip olmak, çocuklarla ihtiyacım olan etkileşimi devre dışı bırakıyor ... bunu bir dosya sürükleme-n olarak düşün -kutu kutusu ... sürükleyip bırakabilir veya dosyalarınızı seçmek için giriş öğesini tıklayabilirsiniz.
Hristo

işte çözümünüzün tatmin etmediğine dair bir örnek ... jsfiddle.net/UnsungHero97/yYF3S/11
Hristo

Kafam karıştı. Neden alt öğelerle de etkileşim kurmanız gerekiyor?
Blender

Benim durumumda, "dropzone" öğesinin alt öğesi bir dosya seçme düğmesidir ... bu nedenle dosyaları sürükleyip bırakmak istemiyorsam, giriş öğesini kullanarak bunları seçebilirim. Ancak yer paylaşımı ile ... Giriş öğesini tıklayamıyorum. mantıklı olmak?
Hristo

@Blender Çoğu durumda bir dosyayı sayfadan değil, masaüstünden sürüklememiz gerekir, bu yüzden bu işe yaramaz.
Mārtiņš Briedis

5

Sorun şu ki, dropzones içindeki elemanlarınız elbette dropzone'un bir parçası ve çocuklara girdiğinizde ebeveynleri terk ediyorsunuz. Bunu çözmek kolay değil. Sınıfınıza tekrar ebeveyninize ekleyerek çocuklara etkinlik eklemeyi deneyebilirsiniz.

$("#dropzone,#dropzone *").on('dragenter', function(event) {

    // add a class to #dropzone

    event.stopPropagation(); // might not be necessary
    event.preventDefault();
    return false;
});

Etkinlikleriniz birden çok kez tetiklenecek, ancak kimse görmeyecek.

// Düzenle: dragleave olayının üzerine kalıcı olarak yazmak için dragmove olayını kullanın:

$("#dropzone,#dropzone *").on('dragenter dragover', function(event) {

    // add a class to #dropzone

    event.stopPropagation(); // might not be necessary
    event.preventDefault();
    return false;
});

Dragleave olayını yalnızca dropzone için tanımlayın.


2
Bu sorunu çözmez. Asıl mesele dragleave... bir çocuğu terk ettiğimde hala ebeveynin içinde olabilirim #dropzoneama bu dragenterolayı bir daha tetiklemeyecek :(
Hristo

Dragenter'ın tekrar ateşlenmediğinden emin misiniz?
Oliver

Ah doğru ... yine işten çıkarıldı, ancak işten kovulduktan sonra, dragleaveolay sadece alt öğe için başlatıldı, bu yüzden yine removeClasstalimat yürütüldü
Hristo

dragleaveSadece #dropzone... için tanımlayamam , eğer yapabilseydim, bu problemi yaşamazdım.
Hristo

Hayır, çocuklara dragleave için olay eklememeyi kastetmiştim.
Oliver

4

As benr belirtilen bu cevap , sen olaylara ateşe alt düğümlerin önleyebilir, ancak bazı olayları bağlamak gerekirse, şunu yapın:

#dropzone.dragover *{
   pointer-events: none;
}

Ve bunu JS kodunuza ekleyin:

$("#dropzone").on("dragover", function (event) {
   $("#dropzone").addClass("dragover");
});

$("#dropzone").on("dragleave", function (event) {
   $("#dropzone").removeClass("dragover");
});

2
Benim için bu, bindirmenin sürekli yanıp sönmesine neden olur.
Andrey Mikhaylov - lolmaus

3

JQuery kullanıyorsanız, şuraya bakın: https://github.com/dancork/jquery.event.dragout

Gerçekten harika.

Gerçek sürükle yaprak işlevselliğini işlemek için özel etkinlik oluşturuldu.

HTML5 dragleave olayı daha çok fareyle benzer şekilde çalışır. Bu eklenti, sürüklerken mouseleave stil işlevselliğini çoğaltmak için oluşturuldu.

Kullanım Örneği:

$ ('# myelement'). on ('dragout', function (event) {// KODUNUZ});

EDIT: aslında, jQuery bağımlı olduğunu sanmıyorum, muhtemelen sadece onsuz bile kullanabilirsiniz.


Vaov! Dragout, dragleaveana dropzone'dan ayrılmamış olsam bile , birçok çocuk öğesinin ateşlediği düzenim için işe yarayan TEK şeydi .
Mark Kasson

Son bir saat boyunca bu konuyla kavga ettikten sonra, dragoutbenim için çalışan tek çözüm oldu.
Jason Hazel

2

@hristo Çok daha zarif bir çözümüm var. Kullanabileceğiniz bir şey olup olmadığını kontrol edin.

Sonuçta çabanız boşa gitmedi. İlk başta sizinkini kullanmayı başardım, ancak FF, Chrome'da farklı sorunlar yaşadım. Çok fazla saat geçirdikten sonra bu öneriyi tam olarak planlandığı gibi çalıştırabildim.

Uygulama şu şekildedir. Kullanıcıları bırakma bölgesi hakkında doğru şekilde yönlendirmek için görsel ipuçlarından da yararlandım.

$(document).on('dragstart dragenter dragover', function(event) {    
    // Only file drag-n-drops allowed, http://jsfiddle.net/guYWx/16/
    if ($.inArray('Files', event.originalEvent.dataTransfer.types) > -1) {
        // Needed to allow effectAllowed, dropEffect to take effect
        event.stopPropagation();
        // Needed to allow effectAllowed, dropEffect to take effect
        event.preventDefault();

        $('.dropzone').addClass('dropzone-hilight').show();     // Hilight the drop zone
        dropZoneVisible= true;

        // http://www.html5rocks.com/en/tutorials/dnd/basics/
        // http://api.jquery.com/category/events/event-object/
        event.originalEvent.dataTransfer.effectAllowed= 'none';
        event.originalEvent.dataTransfer.dropEffect= 'none';

         // .dropzone .message
        if($(event.target).hasClass('dropzone') || $(event.target).hasClass('message')) {
            event.originalEvent.dataTransfer.effectAllowed= 'copyMove';
            event.originalEvent.dataTransfer.dropEffect= 'move';
        } 
    }
}).on('drop dragleave dragend', function (event) {  
    dropZoneVisible= false;

    clearTimeout(dropZoneTimer);
    dropZoneTimer= setTimeout( function(){
        if( !dropZoneVisible ) {
            $('.dropzone').hide().removeClass('dropzone-hilight'); 
        }
    }, dropZoneHideDelay); // dropZoneHideDelay= 70, but anything above 50 is better
});

bazı kapsam dışı değişkenler için tanımları eksik gibi görünüyor, sanırımvar dropZoneHideDelay=70, dropZoneVisible=true;
Timo Huovinen

@TimoHuovinen evet, doğru. Her ikisi dropZoneHideDelay, dropZoneVisiblede 'on'benim uygulamamdaki iki belge olayında gereklidir .
ziyaretler

2

İki sentim: Dropzone'unuzun üzerinde bir katmanı gizleyin, ardından sürükleyiciyi sürüklediğinizde gösterin ve sürükleme yaprakını hedefleyin.

Demo: https://jsfiddle.net/t6q4shat/

HTML

<div class="drop-zone">
  <h2 class="drop-here">Drop here</h2>
  <h2 class="drop-now">Drop now!</h2>
  <p>Or <a href="#">browse a file</a></p>
  <div class="drop-layer"></div>
</div>

CSS

.drop-zone{
  padding:50px;
  border:2px dashed #999;
  text-align:center;
  position:relative;
}
.drop-layer{
  display:none;
  position:absolute;
  top:0;
  left:0;
  bottom:0;
  right:0;
  z-index:5;
}
.drop-now{
  display:none;
}

JS

$('.drop-zone').on('dragenter', function(e){
    $('.drop-here').css('display','none');
    $('.drop-now').css('display','block');
    $(this).find('.drop-layer').css('display','block');
    return false;
});

$('.drop-layer').on('dragleave', function(e){
    $('.drop-here').css('display','block');
    $('.drop-now').css('display','none');
    $(this).css('display','none');
    return false;
});

Basit ve etkili! StopPropagation () yolundan iniyordum ve tüm çocuklara olay işleyici uygulamaktan hoşlanmadım. Dağınık görünüyordu ama bu iyi çalışıyor ve uygulanması basit. İyi bir fikir.
Jon Catmull

1

Bu yüzden benim için yaklaşım pointer-events: none;çok işe yaramadı ... İşte benim alternatif çözümüm:

    #dropzone {
        position: relative;
    }

    #dropzone(.active)::after {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        content: '';
    }

Bu şekilde dragleaveebeveyn (çocukta) veya dragoveralt eleman için mümkün değildir . Bu yardımcı olur umarım :)

* '.Active' sınıfı ben dragenterveya eklediğimde ekliyorum dragleave. Ama eğer onsuz çalışıyorsanız, sadece sınıfı uzak tutun.


1
Bunu bir EmberJS D&D bileşeninde denedim ve 'aktif' sınıfın programsal olarak eklenmesi, farenin ana div'a (ember-view) girdiği zamanın yaklaşık% 40'ı kadar yavaştır. Emin değilim neden. Ama bunu kapalı bırakmak ve harika çalışıyor, bu yüzden bu basit çözüm için teşekkür ederim. Safari, Chrome, Firefox'un en son sürümlerinde (bugün itibariyle) Mac'te test edildi.
rmcsharry

1

Bunun için süper basit hızlı düzeltme, kapsamlı bir şekilde test edilmedi, ancak şu anda Chrome'da çalışıyor.

Kahveyi affedin.

  dragEndTimer = no

  document.addEventListener 'dragover', (event) ->
    clearTimeout dragEndTimer
    $('body').addClass 'dragging'
    event.preventDefault()
    return no

  document.addEventListener 'dragenter', (event) ->
    $('section').scrollTop(0)
    clearTimeout dragEndTimer
    $('body').addClass 'dragging'

  document.addEventListener 'dragleave', (event) ->
    dragEndTimer = setTimeout ->
      $('body').removeClass 'dragging'
    , 50

Bu, Chrome titreme hatasını veya en azından bana sorunlara neden olan permütasyonu giderir.



1

Benim versiyonum:

$(".dropzone").bind("dragover", function(e){
    console.log('dragover');
});

$(".dropzone").bind("dragleave", function(e) {
  var stopDrag = false;
  if (!e.relatedTarget) stopDrag = true;
  else {
    var parentDrop = $(e.relatedTarget).parents('.dropzone');
    if (e.relatedTarget != this && !parentDrop.length) stopDrag = true;
  }

  if (stopDrag) {
    console.log('dragleave');
  }
});

Bu düzen ile:

<div class="dropzone">
  <div class="inner-zone">Inner-zone</div>
</div>

Ben element sınıflarının bir dökümü yaptık e.target, e.currentTarget, e.relatedTargether ikisi için dragoverve dragleaveolaylar.

Bana ebeveyn bloğundan ( .dropzone) ayrılırken e.relatedTargetbu bloğun bir çocuğu olmadığını gösterdi , bu yüzden dropzone dışında olduğumu biliyorum.


0

Burada, en basit çözümlerden biri ● ︿ ●

Bu kemana bir göz atın <- kutunun içine bir dosya sürüklemeyi deneyin

Bunun gibi bir şey yapabilirsiniz:

var dropZone= document.getElementById('box');
var dropMask = document.getElementById('drop-mask');


dropZone.addEventListener('dragover', drag_over, false);
dropMask.addEventListener('dragleave', drag_leave, false);
dropMask.addEventListener('drop', drag_drop, false);

Bununla ne olduğunu burada bilmelisin.
Sadece kemanlara bir bak, biliyorsun.


0

Benzer bir sorun yaşadım ve bu şekilde düzelttim:

Sorun: Fonksiyon bırakma (ev) kullanıcı "bırakma bölgesinde" (ul eleman) bir eleman bıraktığında, fakat maalesef eleman çocuklarından birinde (li elemanlar) düşürüldüğünde de ateşlenir.

Çözüm:

function drop(ev) { 
ev.preventDefault(); 
data=ev.dataTransfer.getData('Text'); 
if(ev.target=="[object HTMLLIElement]")  
{ev.target.parentNode.appendChild(document.getElementById(data));}
else{ev.target.appendChild(document.getElementById(data));} 
} 

0

Kullanıcılar alanı bir dosyaya sürüklediğinde kutu rengi değişecek bir dosya yükleme kutusu için bu kendimi uygulamaya çalışıyordu.

Javascript ve CSS'nin güzel bir karışımı olan bir çözüm buldum. Eğer bir droppable bölge olduğunu varsayalım divkimliğine sahip #drop. Bunu Javascript'inize ekleyin:

$('#drop').on('dragenter', function() {
    $(this).addClass('dragover');
    $(this).children().addClass('inactive');
});

$('#drop').on('dragleave', function() {
    $(this).removeClass('dragover');
    $(this).children().removeClass('inactive');
});

Daha sonra, tüm çocukları devre dışı bırakmak için CSS'nize ekleyin .inactive:

#drop *.inactive {
    pointer-events: none;
}

Bu nedenle, kullanıcı öğeyi kutunun üzerine sürüklediği sürece alt öğeler etkin olmaz.


0

Burada sunulan geçici çözümlerin hiçbirinden memnun hissetmedim, çünkü çocuk öğeleri üzerinde kontrolü kaybetmek istemiyorum.

Bu yüzden farklı bir mantık yaklaşımı kullandım, jquery-draghandler adı verilen bir jQuery eklentisine çevirdim . Yüksek performansları garanti ederek kesinlikle DOM'yi manipüle etmez. Kullanımı basit:

$(document).ready(function() {

    $(selector).draghandler({
        onDragEnter: function() {
            // $(this).doSomething();
        },
        onDragLeave: function() {
            // $(this).doSomethingElse();
        }
    });

});

Herhangi bir DOM işlevinden ödün vermeden problemle kusursuz bir şekilde ilgilenir.

Git deposunda indirme, ayrıntılar ve açıklamalar .


Eklentinizde drag enter olayını nasıl alabilirim?
Woody

Direktifinizi gerçekten test etmedim, ancak ana eleman (A) aslında (B) için kontrol etmek istediğim öğeyi çevrelemezse işe yaramadığını düşünüyorum. Örneğin, B'nin alt kenarı ile A'nın alt kenarı arasında dolgu yoksa, sürükleyici asla A elemanı için ateşlenmez, değil mi?
marcelj

@marcelj A öğesi gövde belgesinin kendisi olabilir, bu nedenle minimum dolgu ile gerçekten çevreleyen bir öğeye (gövde işi yapar) ihtiyacınız yoktur. Bu yaklaşımla daha sonra bulduğum sınırlama, eğer frames ile çalışıyorsanız ve elemanınız onun sınırındaysa. Bu durumda, bu yaklaşımı önermiyorum.
Luca Fagioli

0

Aslında https://github.com/lolmaus/jquery.dragbetter/ adresinde gördüklerimi beğeniyorumancak olası bir alternatifi paylaşmak istedim. Genel stratejim, dropzone'a (çocuklarına değil) sürüklerken ya da herhangi bir çocuğunu (köpürme yoluyla) bir arka plan stili uygulamaktı. Sonra bırakma bölgesini sürüklerken stili kaldırırım. Fikir bir çocuğa taşınırken, stili dropzone'dan çıkarken bile (dragleave yangınları) kaldırsam bile, stili herhangi bir çocuğu sürükleyerek ebeveyn dropzone'a tekrar uygularım. Sorun, elbette, dropzone'dan dropzone'un bir çocuğuna geçerken, dragenter, dragleave'dan önce çocuğa ateşlenir, böylece stillerim düzensiz olarak uygulanır. Benim için çözüm, dragenter olayını tekrar mesaj kuyruğuna zorlamak için bir zamanlayıcı kullanmaktı ve sürükleme yaprakından SONRA işleme koymamı sağladı. Zamanlayıcı geri aramasında olaya erişmek için bir kapak kullandım.

$('.dropzone').on('dragenter', function(event) {
  (function (event) {
    setTimeout(function () {
      $(event.target).closest('.dropzone').addClass('highlight');
    }, 0);
  }) (event.originalEvent); 
});

Bu, kromda, yani firefox'ta ve dropzone'daki çocuk sayısından bağımsız olarak çalışıyor gibi görünüyor. Olayların yeniden oluşturulmasını garanti eden zaman aşımı konusunda biraz tedirginim, ancak kullanım durumum için oldukça iyi çalışıyor gibi görünüyor.


0

Bunu kendim uygulamaya çalışıyordum ve Jquery veya herhangi bir eklenti de istemiyordum.

Ben dosya yükleme işlemek istedim, aşağıdaki şekilde benim için en iyi kabul:

Dosya Yapısı:

--- / uploads {yükleme dizini}

--- /js/slyupload.js {javascript dosyası.}

--- index.php

--- upload.php

--- styles.css {sadece küçük bir stil ..}

HTML Kodu:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>my Dzone Upload...</title>
<link rel="stylesheet" href="styles.css" />
</head>

<body>
    <div id="uploads"></div>        
    <div class="dropzone" id="dropzone">Drop files here to upload</div>     
    <script type="text/javascript" src="js/slyupload.js"></script>      
</body>
</html>

O zaman bu ekli Javascript dosyası :: 'js / slyupload.js'

<!-- begin snippet:  -->

<!-- language: lang-js -->

    // JavaScript Document

    //ondragover, ondragleave...


    (function(){        

        var dropzone = document.getElementById('dropzone');
        var intv;

        function displayUploads(data){
            //console.log(data, data.length);
            var uploads = document.getElementById('uploads'),anchor,x;

            for(x=0; x < data.length; x++){

                //alert(data[x].file);
                anchor = document.createElement('a');
                anchor.href = data[x].file;
                anchor.innerText = data[x].name;

                uploads.appendChild(anchor);
            }               
        }

        function upload(files){
            //console.log(files);
            var formData = new FormData(), 
                xhr      = new XMLHttpRequest(),    //for ajax calls...
                x;                                  //for the loop..

                for(x=0;x<files.length; x++){
                    formData.append('file[]', files[x]);

                    /*//do this for every file...
                    xhr = new XMLHttpRequest();

                    //open... and send individually..
                    xhr.open('post', 'upload.php');
                    xhr.send(formData);*/
                }

                xhr.onload = function(){
                    var data = JSON.parse(this.responseText);   //whatever comes from our php..
                    //console.log(data);
                    displayUploads(data);

                    //clear the interval when upload completes... 
                    clearInterval(intv);
                }                   

                xhr.onerror = function(){
                    console.log(xhr.status);
                }

                //use this to send all together.. and disable the xhr sending above...

                //open... and send individually..
                intv = setInterval(updateProgress, 50);
                xhr.open('post', 'upload.php');
                xhr.send(formData);

                //update progress... 
                 /* */                   
        }

        function updateProgress(){
            console.log('hello');
         }          

        dropzone.ondrop = function(e){
            e.preventDefault(); //prevent the default behaviour.. of displaying images when dropped...
            this.className = 'dropzone';
            //we can now call the uploading... 
            upload(e.dataTransfer.files); //the event has a data transfer object...
        }

        dropzone.ondragover = function(){
            //console.log('hello');
            this.className = 'dropzone dragover';
            return false;
        }

        dropzone.ondragleave = function(){
            this.className = 'dropzone';
            return false;
        }           
    }(window));

CSS:

body{
	font-family:Arial, Helvetica, sans-serif; 
	font-size:12px;
}

.dropzone{
	width:300px; 
	height:300px;
	border:2px dashed #ccc;
	color:#ccc;
	line-height:300px;
	text-align:center;
}

.dropzone.dragover{
	border-color:#000;
	color:#000;
}


0

Üzgünüm jquery değil javascript, ama benim için bunu çözmenin en mantıklı yolu. Tarayıcı, dropenter'dan (önceki elemanın) (yeni elemanın) dropleave çağırmalıdır, çünkü bir şey forst şeyden ayrılmadan önce başka bir şey giremez, neden yaptığını anlamıyorum! de dropleave böyle:

function mydropleave(e)
{
    e.preventDefault();
    e.stopPropagation();

    setTimeout(function(e){ //the things you want to do },1);
}

Ve damlacı damla yapraklarından sonra olacak, hepsi bu!


-1

greedy : trueÇocuğun işlevini olarak kullanın droppable. Ardından yalnızca ilk katmanı tıklatıp olayı başlatın.

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.