親要素の「ドラッグリーブ」は、子要素の上にドラッグすると発生します


163

概観

次のHTML構造があり、dragenterおよびdragleaveイベントを<div id="dropzone">要素にアタッチしました。

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

問題

私は上のファイルをドラッグすると<div id="dropzone">dragenter期待通りにイベントが発生します。私は子要素の上に私のマウスを移動すると、しかし、のような<div id="drag-n-drop">dragenterイベントが焼成された<div id="drag-n-drop">要素と、その後dragleaveのイベントがために解雇される<div id="dropzone">要素。

<div id="dropzone">要素に再びカーソルを合わせると、dragenterイベントが再び発生しますが、これはクールですがdragleave、子要素の残りのイベントが発生するため、removeClass命令は実行されます。

この動作には2つの理由で問題があります。

  1. dragenterdragleaveをアタッチしているだけな<div id="dropzone">ので、子要素にこれらのイベントもアタッチされている理由がわかりません。

  2. <div id="dropzone">子の上にカーソルを置いている間も要素をドラッグしているのでdragleave、発砲したくありません!

jsFiddle

jsFiddleをいじくり回します。 http

質問

だから...どうすれば、<div id="dropzone">要素の上にファイルをドラッグしているときにdragleave、子要素の上にドラッグしていても起動しないようにすることができます...要素を離れたときにのみ起動する必要があり<div id="dropzone">ます。要素の境界内の任意の場所でホバリング/ドラッグしても、イベントトリガーされませんdragleave

これは、少なくともHTML5のドラッグアンドドロップをサポートするブラウザーでは、ブラウザー間の互換性が必要なので、この答えは適切ではありません。

GoogleとDropboxはこれを理解しているようですが、それらのソースコードは縮小化/複雑化されているため、実装からこれを理解することができませんでした。


イベントの伝播を防止e.stopPropagation();
Blender

私はすでにそうだと思います...アップデートをチェックしてください
Hristo

jsfiddle.netのどこかにデモを投稿できますか?
Blender

@ブレンダー...確かに、数分待ってください!
Hristo

@Blender ...私はフィドルで質問を更新しました
Hristo

回答:


171

イベントを子要素にバインドする必要がない場合は、常にpointer-eventsプロパティを使用できます。

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

4
最高のソリューション!私はcssを使ってこのようなエレガントな方法で問題を解決できるとは思いもしませんでした。どうもありがとうございました!
serg66 2013年

1
そうそう。これだよ!
mcmlxxxiii 2013年

23
このアプローチの唯一の欠点は、子要素のすべてのポインターイベントを処理することです(たとえば、個別の:hoverスタイルやクリックイベントハンドラーを持つことができなくなります)。これらのイベントを保持したい場合に備えて、私が使用してきた別の回避策を次に示し
Ben

2
ドロップゾーンのすべての子に到達するためにcss子セレクターと組み合わせる: .dropzone * {pointer-events: none;}
Philipp F

7
あなたはすでにjQueryを使用しているので$('.element').addClass('dragging-over')、ドラッグしている要素に、そして$('.element').removeClass('dragging-over')ドラッグしたときだけです。それからあなたのCSSであなたは持つことができます.element.dragging-over * { pointer-events: none; }。これにより、ドラッグしているときにのみ、すべての子要素からポインターイベントが削除されます。
ギャビン、

56

ようやく、満足できる解決策を見つけました。実際にいくつかの方法を見つけましたが、現在の解決策ほどうまくいかなかったものがあります。1つの解決策では、#dropzone要素に境界線を追加/削除した結果、ちらつきが頻繁に発生しました...別の境界では、ブラウザから離れた場所に移動した場合は削除されませんでした。

とにかく、私の最高のハックソリューションはこれです。

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

これはかなりうまくいきますが、Firefoxで問題が発生dragenterしました。これは、Firefoxが二重に起動していたため、カウンターがオフになっていたためです。それにもかかわらず、それは非常にエレガントなソリューションではありません。

それから私はこの質問に出会いましたウィンドウの外にドラッグしたときにFirefoxでdragleaveイベントを検出する方法

だから私は答えを取りそれを私の状況に適用しました:

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

これはクリーンでエレガントで、これまでにテストしたすべてのブラウザーで動作しているようです(まだIEをテストしていません)。


これが今のところ最良の解決策です。唯一の問題は、ファイルを追加して削除し、その上に別のファイルをドラッグすると、このコードが機能しないことです。HoverEndを発生させ、HoverStartを再度発生させた後にのみ、このコードは再び機能します。
MysticEarth

@MysticEarthが機能しない場合、jsFiddleを組み合わせてデモを行うことができますか?
Hristo

1
お返事ありがとうございます。HTML5のドラッグアンドドロップインターフェイスとイベントリスナーは非常に苦痛になる可能性があるため、これは本当に役に立ちました。これは、特にドロップゾーン要素の複数のインスタンスを処理する場合に、クレイジーなイベントを処理するための最良の方法です。
ニコO

stopPropagation()preventDefault()を呼び出してfalseを返す必要があるのはなぜですか。falseを返すだけで十分です。それでいいの?
Dejo

これは冗長ですが、呼び出しstopPropagation()preventDefault()優先されます。ドロップしreturn falseます。
Peeja

38

これは少し醜いですが、それはおかしく動作します!...

'dragenter'ハンドラーでevent.targetを(クロージャー内の変数などに)保存してから、 'dragleave'ハンドラーでevent.target ===保存したものの場合にのみコードを起動します。

望まないときに「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");
        }
    });

}());

これは後で試すつもりです。どちらかと言えば、私のソリューションよりも見た目はきれいですが、ブラウザ間でどのように互換性があるかは、見ただけではわかりません。これをどこでテストしましたか?
Hristo 2012

1
Chromeのみであり、子要素とコンテナの間に物理的なギャップがあるという前提でのみ機能します。
hacklikecrack 2012

5
ここで私のお気に入りの答え。醜い感じはまったくありません:)
Matt Way

1
IE、Chrome、FFで機能する
Vicentiu Bacioiu 2014

1
ドラッグが子で始まる場合、これは機能しません。たとえば、別のウィンドウの何かから、子の内部でドラッグが始まるようにドラッグします。
FINDarkside

29

最初、私は人々がそのpointer-events: noneアプローチを捨てることに同意しました。しかし、私は自分自身に尋ねました:

ドラッグの進行中に子要素を操作するために、ポインタイベントが本当に必要ですか?

私の場合、子供たちにはたくさんのことが起こっています。たとえば、ホバーして追加のアクションのボタンを表示したり、インライン編集をしたりします。しかし、ドラッグ中に必要なことはなく、実際には望まいません

私の場合、私は次のようなものを使用して、親コンテナーのすべての子ノードに対してポインターイベントを選択的にオフにします。

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

お好みの方法を使用してdragging-in-progressdragEnter/ dragLeaveイベントハンドラーでクラスを追加/削除しますdragStart。al。


1
この解決策は最も単純であり、(私が知る限り)完全に証明されています。dragstartイベントにクラスを追加し、で削除するだけですdragend
cmann

これはかなり良い解決策ですが、完璧ではありません。子要素でドラッグが開始された場合(別のウィンドウからドラッグ)、dragEnterは発生しません。おそらく、子に移動したときにdragEnterが起動されないほど十分速くマウスを動かすことも可能ですが、100%確実ではありません。
FINDarkside

12

これはChromeのバグのようです。

私が考えることができる唯一の回避策は、イベントをキャプチャする透明なオーバーレイ要素を作成することでした: 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>

答えてくれてありがとう、Blender。しかし、私はすでにこれを試しました。このソリューションの問題は、オーバーレイ要素が対話する必要のある子要素を「オーバーレイ」することです...そのため、オーバーレイを使用すると、子との必要な対話が無効になります...ファイルのドラッグアンドドロップと考えてください-ドロップボックス...ドラッグアンドドロップするか、入力要素をクリックしてファイルを選択できます。
Hristo

これは、ソリューションが満たさないフィドルの例です... jsfiddle.net/UnsungHero97/yYF3S/11
Hristo

よくわかりません。なぜ子要素も操作する必要があるのですか?
Blender

私の場合、「dropzone」の子要素はファイル選択ボタンです...ファイルをドラッグアンドドロップしたくない場合は、input要素を使用してファイルを選択できます。しかし、オーバーレイでは... input要素をクリックできません。理にかなっていますか?
Hristo

@Blenderほとんどの場合、ページから要素ではなく、デスクトップからファイルをドラッグする必要があるため、この方法は機能しません。
マルティンスBriedis

5

問題は、ドロップゾーン内の要素はもちろんドロップゾーンの一部であり、子を入力すると親から離れることです。これを解決するのは簡単ではありません。子にイベントを追加して、親にクラスを再度追加してみてください。

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

    // add a class to #dropzone

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

イベントは引き続き複数回発生しますが、誰も表示しません。

//編集:dragmoveイベントを使用して、dragleaveイベントを永続的に上書きします。

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

    // add a class to #dropzone

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

ドロップゾーンに対してのみdragleaveイベントを定義します。


2
それでも問題は解決しません。本当の問題はdragleave...私が子供を残したとき、私はまだ親の中にいるかもしれません#dropzoneが、それはdragenterイベントを再び発生させません:(
Hristo

dragenterが再び発砲されないことを確信していますか?
Oliver

ああ、そうです...再び発生しますが、発生後、dragleaveイベントはすぐに残った子要素に対して発生するので、再びremoveClass命令が実行されます
Hristo

... dragleaveだけを定義することはできません#dropzone。できれば、この問題は発生しません。
Hristo

いいえ、ドラッグリーブのイベントを子供に追加しないことを意味しました。
Oliver

4

以下のようbenrがで述べたこの答えは、イベントに火災に子ノードを防ぐことができますが、あなたには、いくつかのイベントをバインドする必要がある場合は、次の操作を行います。

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

そして、これをJSコードに追加してください:

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

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

2
私にとって、これはオーバーレイが絶え間なく点滅することになります。
Andrey Mikhaylov-lolmaus 14年

3

jQueryを使用している場合は、これを確認してください。 ご覧ください。https //github.com/dancork/jquery.event.dragout

それは本当に素晴らしいです。

真のドラッグリーブ機能を処理するために作成された特別なイベント。

HTML5 dragleaveイベントは、マウスアウトのように機能します。このプラグインは、ドラッグ中のマウスリーブスタイルの機能を複製するために作成されました。

使用例:

$( '#myelement')。on( 'dragout'、function(event){//あなたのコード});

編集:実際には、それはjQueryに依存しているとは思いません、おそらくそれなしでもコードを使用できます。


うわー!ドラッグアウトは、私が親ドロップゾーンをdragleave離れていなくても、たくさんの子要素が発火する私のレイアウトで機能した唯一のものです。
Mark Kasson、

最後の1時間この問題と戦った後dragout、私のために働いた唯一の解決策でした。
Jason Hazel

2

@hristo私ははるかにエレガントな解決策を持っています。それがあなたが使えるものかどうかを確認してください。

結局あなたの努力は無駄になりませんでした。最初はなんとか使いましたが、FF、Chromeで別の問題がありました。多くの時間を費やした後、私はその提案を意図したとおりに機能させました。

実装方法は次のとおりです。また、視覚的な手がかりを利用して、ドロップゾーンについてユーザーを正しくガイドしました。

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

あなたは、私が想定し、スコープ変数のいくつかのうちの定義が欠落しているようだvar dropZoneHideDelay=70, dropZoneVisible=true;
ティモHuovinen

@TimoHuovinenはい、正しいです。私の実装では、dropZoneHideDelay, dropZoneVisible2つの'on'ドキュメントイベントにわたって両方が必要です。
Visitsb 2014年

2

私の2セント:ドロップゾーンの上にレイヤーを非表示にし、dragenter時にレイヤーを表示し、その上にドラッグリーブをターゲットにします。

デモ: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;
});

シンプルで効果的!stopPropagation()ルートをたどっていたので、すべての子にイベントハンドラーを適用したくありませんでした。乱雑に見えましたが、これはうまく機能し、実装は簡単です。良いアイデア。
Jon Catmull 2017年

1

だから私にとってアプローチ pointer-events: none;はあまりうまくいきませんでした...だからここに私の代替ソリューションがあります:

    #dropzone {
        position: relative;
    }

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

この方法では、 dragleave、(子の)親またはdragover子要素。お役に立てれば :)

* I dragenterまたはのときに追加する「.active」クラスdragleave。しかし、それなしで作業している場合は、クラスを離れてください。


1
EmberJS D&Dコンポーネントでこれを試してみました。プログラムで「アクティブ」クラスを追加すると、マウスが親div(ember-view)に入る時間の約40%が遅すぎます。なぜだかわかりません。しかし、それをオフにすると、うまく機能するので、この単純な解決策に感謝します。Safari、Chrome、Firefoxの最新バージョン(現在)のMacでテストされています。
rmcsharry 2016

1

これに対する非常にシンプルなクイックフィックス。広範囲にテストされていませんが、現在Chromeで動作します。

失礼しました。

  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

これにより、Chromeのちらつきのバグが修正されます。少なくとも、問題の原因となっていたその順列が修正されます。



1

私のバージョン:

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

このレイアウトでは:

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

私はのための要素クラスのダンプを作ったe.targete.currentTargete.relatedTarget両方のためにdragoverdragleaveイベント。

親ブロック(.dropzone)を離れると、e.relatedTargetこのブロックの子ではないので、ドロップゾーンの外にいることがわかりました。


0

ここで、最も簡単な解決策の1つ●︿●

このフィドルを見てください<-ボックス内にファイルをドラッグしてみてください

あなたはこのようなことをすることができます:

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

それによって、ここで何が起こっているかをすでに知っているはずです。
フィドルをご覧ください。


0

私は同様の問題を抱えていて、次のように修正しました:

問題:関数「drop(ev)」は、ユーザーが「ドロップゾーン」(ul要素)に要素をドロップしたときに発生しますが、残念ながら、その要素がその子(li要素)の1つにドロップされたときにも発生します。

修正:

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

ユーザーがファイルをスペースにドラッグしたときにボックスの色が変化するファイルアップロードボックスに対して、これを自分で実装しようとしました。

JavaScriptとCSSをうまく組み合わせたソリューションを見つけました。divID が付いたドロップ可能なゾーンがあるとし#dropます。これをJavascriptに追加します。

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

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

次に、これをCSSに追加して、すべての子will classを非アクティブ化します.inactive

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

したがって、ユーザーがボックスの上に要素をドラッグしている限り、子要素は非アクティブになります。


0

子要素の制御を失いたくないので、ここに示した回避策のいずれにも満足しませんでした。

したがって、私は別のロジックアプローチを使用して、それをjquery-draghandlerと呼ばれるjQueryプラグインに変換しました。DOMを絶対に操作しないため、高いパフォーマンスが保証されます。使い方は簡単です:

$(document).ready(function() {

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

});

DOMの機能を損なうことなく、問題を完璧に処理します。

Gitリポジトリーのダウンロード、詳細、説明。


プラグインでdrag enterイベントを取得するにはどうすればよいですか?
ウッディ、

私は実際にディレクティブをテストしていませんが、親要素(A)が確認したい要素(B)を実際に囲んでいない場合は機能しないと思います。たとえば、Bの下端とAの下端の間にパディングがない場合、dragenterは要素Aに対して起動されませんよね?
marcelj 2016年

@marcelj要素Aは本文ドキュメント自体にすることができるため、最小限のパディングで周囲の要素(本文が処理を行う)は実際には必要ありません。このアプローチで後で発見した制限は、framesを操作していて、要素がその境界にある場合です。その場合、このアプローチはお勧めしません。
Luca Fagioli、2016

0

私は実際にhttps://github.com/lolmaus/jquery.dragbetter/で見たものを好みますしかし、可能な代替案を共有したかった。私の一般的な戦略は、(バブリングによって)ドラッグゾーンまたはその子にドラッグ入力するときに、ドロップゾーン(子ではない)に背景スタイルを適用することでした。次に、ドロップゾーンをドラッグリーブするときにスタイルを削除します。子に移動するときに、ドロップゾーンからスタイルを削除しても(ドラッグリーブが発火します)、任意の子をドラッグして親のドロップゾーンにスタイルを再適用するだけです。もちろん問題は、dropzoneからdropzoneの子に移動すると、dragleaveの前にdragenterが子で発生するため、スタイルが順不同に適用されることです。私のための解決策は、タイマーを使用してdragenterイベントをメッセージキューに強制的に戻し、dragleaveの後で処理できるようにすることでした。クロージャーを使用して、タイマーコールバックでイベントにアクセスしました。

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

これはChrome、つまりFirefoxで機能するようで、ドロップゾーンの子の数に関係なく機能します。イベントの再シーケンスを保証するタイムアウトについては少し不安ですが、私のユースケースではかなりうまくいくようです。


0

私はこれを自分で実装しようとしていましたが、Jqueryもプラグインも必要ありませんでした。

私がファイルのアップロードを処理したかったので、次のようにして自分に最適だと考えました。

ファイル構造:

--- / uploads {アップロードディレクトリ}

--- /js/slyupload.js {JavaScriptファイル。}

--- index.php

--- upload.php

--- styles.css {ちょっとしたスタイリング..}

HTMLコード:

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

次に、これは添付のJavaScriptファイルです:: '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

申し訳ありませんがjqueryではなくjavascriptですが、私にとってはそれを解決する最も論理的な方法です。ブラウザは、(前の要素の)dropleaveを、(新しい要素の前に)dropenterの前に呼び出す必要があります。何かが何かに入ることができないため、最初のものを離れる必要があるため、なぜそうしたのか理解できません!そのようなドロップリーブ:

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

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

そして、dropenterはdropleaveの後に発生します、それだけです!


-1

greedy : true関数として子にを使用しdroppableます。次に、最初のレイヤーでクリックされたイベントのみを開始します。

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