web-dev-qa-db-ja.com

子要素をホバーするときに発生するHTML5 dragleave

私が抱えている問題は、要素のdragleaveイベントがその要素の子要素をホバリングするときに発生することです。また、親要素を再度ホバリングすると、dragenterは発生しません。

簡略化したフィドルを作成しました: http://jsfiddle.net/pimvdb/HU6Mk/1/

HTML:

<div id="drag" draggable="true">drag me</div>

<hr>

<div id="drop">
    drop here
    <p>child</p>
    parent
</div>

次のJavaScriptを使用します。

$('#drop').bind({
                 dragenter: function() {
                     $(this).addClass('red');
                 },

                 dragleave: function() {
                     $(this).removeClass('red');
                 }
                });

$('#drag').bind({
                 dragstart: function(e) {
                     e.allowedEffect = "copy";
                     e.setData("text/plain", "test");
                 }
                });

行うべきことは、そこに何かをドラッグするときにドロップdivを赤にしてユーザーに通知することです。これは機能しますが、p子にドラッグすると、dragleaveが起動され、divは赤ではなくなります。ドロップdivに戻っても、再び赤くなることはありません。ドロップdivから完全に移動し、再びドラッグして赤にする必要があります。

子要素にドラッグするときにdragleaveが発火するのを防ぐことはできますか?

2017 Update:TL; DR、最新のブラウザとIE11で動作する以下の@ H.D。の回答に記載されているCSS pointer-events: none;を検索します。

261
pimvdb

必要なのは、参照カウンタを保持し、dragenterを取得するときにインクリメントし、dragleaveを取得するときにデクリメントするだけです。カウンターが0の場合-クラスを削除します。

var counter = 0;

$('#drop').bind({
    dragenter: function(ev) {
        ev.preventDefault(); // needed for IE
        counter++;
        $(this).addClass('red');
    },

    dragleave: function() {
        counter--;
        if (counter === 0) { 
            $(this).removeClass('red');
        }
    }
});

注:ドロップイベントで、カウンターをゼロにリセットし、追加したクラスをクリアします。

実行できます here

299
Woody

子要素にドラッグするときにdragleaveが発火するのを防ぐことはできますか?

はい。

#drop * {pointer-events: none;}

そのCSSはChromeに十分なようです。

Firefoxで使用する場合、#dropにテキストノードを直接含めることはできません(そうでない場合は、奇妙な 要素が「そのまま」という問題 )、したがって、1つの要素のみを残すことをお勧めします(たとえば、#drop内でdivを使用してすべてを内部に配置します)

こちらはjsfiddleです元の質問(壊れた)例 を解きます。

また、@ Theodore Brownの例から 簡易版 forkを作成しましたが、このCSSのみに基づいています。

ただし、すべてのブラウザにこのCSSが実装されているわけではありません: http://caniuse.com/pointer-events

Facebookのソースコードを見ると、このpointer-events: none;を数回見つけることができましたが、おそらくグレースフルデグラデーションフォールバックと一緒に使用されています。少なくともそれはとても簡単で、多くの環境で問題を解決します。

69
H.D.

ここでは、最も単純なクロスブラウザソリューション(真剣に):

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

次のようなことができます:

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

簡単に言うと、ドロップゾーン内に「マスク」を作成し、幅と高さを継承し、絶対位置を指定します。これは、ドラッグオーバーの開始時に表示されます。
したがって、そのマスクを表示した後、他のdragleave&dropイベントをアタッチすることで、トリックを行うことができます。

離れるか、ドロップした後、あなたは再びマスクを非表示にします。
シンプルで合併症なし。

(Obs .: Greg Pettitのアドバイス-境界線を含めて、マスクが箱全体を覆っていることを確認する必要があります)

43

この問題を解決する「正しい」方法は、ドロップターゲットの子要素でのポインターイベントを無効にすることです(@ H.D。の答えのように)。 これは、この手法を実証するために作成したjsFiddleです 。残念ながら、これはIE11より前のバージョンのInternet Explorerでは機能しません。これは、それらが ポインターイベントをサポートしていない であるためです。

幸いなことに、IEの古いバージョンでdoes動作する回避策を思いつくことができました。基本的に、子要素の上にドラッグしたときに発生するdragleaveイベントを識別して無視します。 dragenterイベントは親のdragleaveイベントの前に子ノードで発生するため、「ignore-drag-leave」クラスを追加または削除する個別のイベントリスナーを各子ノードに追加できます。ドロップターゲット。次に、ドロップターゲットのdragleaveイベントリスナーは、このクラスが存在するときに発生する呼び出しを単に無視できます。 この回避策を示すjsFiddle です。 Chrome、Firefox、IE8 +でテストされ、動作しています。

更新:

複合ソリューションを示すjsFiddle 機能検出を使用し、サポートされている場合はポインターイベントが使用され(現在はChrome、Firefox、およびIE11)、ポインターイベントの場合はブラウザーが子ノードへのイベントの追加にフォールバックしますサポートは利用できません(IE8-10)。

34
Theodore Brown

この質問が行われ、多くの解決策(いハッキングを含む)が提供されてからかなり時間が経ちました。

私はこの問題の答えのおかげで最近抱えていた同じ問題を解決することができました answer そしてそれは誰かに役立つかもしれないと思った誰がこのページにアクセスします。全体的な考え方は、親要素または子要素のいずれかで呼び出されるたびにevenet.targetondrageenterに格納することです。次に、ondragleaveで、現在のターゲット(event.target)がondragenterに保存したオブジェクトと等しいかどうかを確認します。

これら2つが一致するのは、ドラッグがブラウザウィンドウを離れるときだけです。

これが正常に機能する理由は、マウスが要素(たとえばel1)を離れて別の要素(たとえばel2)に入ると、最初にel1.ondragenterが呼び出され、次にel2.ondragleaveが呼び出されるためです。 。ドラッグがブラウザウィンドウを出入りするときのみ、event.target''el1.ondragenterの両方でel2.ondragleaveになります。

これが私の作業サンプルです。 IE9 +、Chrome、Firefox、Safariでテストしました。

(function() {
    var bodyEl = document.body;
    var flupDiv = document.getElementById('file-drop-area');

    flupDiv.onclick = function(event){
        console.log('HEy! some one clicked me!');
    };

    var enterTarget = null;

    document.ondragenter = function(event) {
        console.log('on drag enter: ' + event.target.id);
        enterTarget = event.target;
        event.stopPropagation();
        event.preventDefault();
        flupDiv.className = 'flup-drag-on-top';
        return false;
    };

    document.ondragleave = function(event) {
        console.log('on drag leave: currentTarget: ' + event.target.id + ', old target: ' + enterTarget.id);
        //Only if the two target are equal it means the drag has left the window
        if (enterTarget == event.target){
            event.stopPropagation();
            event.preventDefault();
            flupDiv.className = 'flup-no-drag';         
        }
    };
    document.ondrop = function(event) {
        console.log('on drop: ' + event.target.id);
        event.stopPropagation();
        event.preventDefault();
        flupDiv.className = 'flup-no-drag';
        return false;
    };
})();

そして、これは単純なhtmlページです。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Multiple File Uploader</title>
<link rel="stylesheet" href="my.css" />
</head>
<body id="bodyDiv">
    <div id="cntnr" class="flup-container">
        <div id="file-drop-area" class="flup-no-drag">blah blah</div>
    </div>
    <script src="my.js"></script>
</body>
</html>

適切なスタイリングでは、ユーザーがファイルを適切な場所に簡単にドロップできるように、ファイルが画面にドラッグされるたびに内側のdiv(#file-drop-area)を大きくすることです。

26
Ali Motevallian

問題は、マウスが子要素の前に来るとdragleaveイベントが発生することです。

e.target要素がthis要素と同じかどうかを確認するさまざまな方法を試しましたが、改善は得られませんでした。

この問題を修正する方法は少しハッキングでしたが、100%動作します。

dragleave: function(e) {
               // Get the location on screen of the element.
               var rect = this.getBoundingClientRect();

               // Check the mouseEvent coordinates are outside of the rectangle
               if(e.x > rect.left + rect.width || e.x < rect.left
               || e.y > rect.top + rect.height || e.y < rect.top) {
                   $(this).removeClass('red');
               }
           }
14
Greg

非常に簡単な解決策は、 pointer-events CSSプロパティ を使用することです。すべての子要素でdragstartに値をnoneに設定するだけです。これらの要素は、マウス関連のイベントをトリガーしなくなります。そのため、それらの上でマウスをキャッチすることはなく、したがって、dragleave親。

ドラッグの終了時に、このプロパティをautoに戻すことを忘れないでください;)

9
FruityFred

hTML5を使用している場合、親のclientRectを取得できます。

let rect = document.getElementById("drag").getBoundingClientRect();

次に、parent.dragleave()で:

dragleave(e) {
    if(e.clientY < rect.top || e.clientY >= rect.bottom || e.clientX < rect.left || e.clientX >= rect.right) {
        //real leave
    }
}

こちらはjsfiddleです

9
azlar

Firefoxで修正するには、 jQueryソースコード から少しインスピレーションを得ます。

dragleave: function(e) {
    var related = e.relatedTarget,
        inside = false;

    if (related !== this) {

        if (related) {
            inside = jQuery.contains(this, related);
        }

        if (!inside) {

            $(this).removeClass('red');
        }
    }

}

残念ながら、それはChromeでは機能しません。なぜなら、 relatedTargetdragleaveイベントに存在しないようであり、あなたの例ではChromeで作業していると思いますFirefoxでは動作しません。 ここにバージョンがあります 上記のコードが実装されています。

8
robertc

そして、Chromeのソリューションです。

.bind('dragleave', function(event) {
                    var rect = this.getBoundingClientRect();
                    var getXY = function getCursorPosition(event) {
                        var x, y;

                        if (typeof event.clientX === 'undefined') {
                            // try touch screen
                            x = event.pageX + document.documentElement.scrollLeft;
                            y = event.pageY + document.documentElement.scrollTop;
                        } else {
                            x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
                            y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
                        }

                        return { x: x, y : y };
                    };

                    var e = getXY(event.originalEvent);

                    // Check the mouseEvent coordinates are outside of the rectangle
                    if (e.x > rect.left + rect.width - 1 || e.x < rect.left || e.y > rect.top + rect.height - 1 || e.y < rect.top) {
                        console.log('Drag is really out of area!');
                    }
                })
7
Aldekein

Document.elementFromPointを使用した別のソリューションを次に示します。

 dragleave: function(event) {
   var event = event.originalEvent || event;
   var newElement = document.elementFromPoint(event.pageX, event.pageY);
   if (!this.contains(newElement)) {
     $(this).removeClass('red');
   }
}

これがうまくいくことを願って、ここに fiddle があります。

6
marcelj

簡単な解決策は、CSSルールpointer-events: noneを子コンポーネントに追加して、ondragleaveのトリガーを防ぐことです。例を参照してください:

function enter(event) {
  document.querySelector('div').style.border = '1px dashed blue';
}

function leave(event) {
  document.querySelector('div').style.border = '';
}
div {
  border: 1px dashed silver;
  padding: 16px;
  margin: 8px;
}

article {
  border: 1px solid silver;
  padding: 8px;
  margin: 8px;
}

p {
  pointer-events: none;
  background: whitesmoke;
}
<article draggable="true">drag me</article>

<div ondragenter="enter(event)" ondragleave="leave(event)">
  drop here
  <p>child not triggering dragleave</p>
</div>
6
Alexandre Annic

この正確な問題を処理するために Dragster と呼ばれる小さなライブラリを作成しました。IE(DOM Event Constructorsをサポートしていませんが、 jQueryのカスタムイベントを使用して似たようなものを簡単に記述できます)

5
Ben

ドラッグされた要素が子であるかどうかを確認し、子である場合は、「ドラッグオーバー」スタイルクラスを削除しないでください。非常にシンプルで私のために働く:

 $yourElement.on('dragleave dragend drop', function(e) {
      if(!$yourElement.has(e.target).length){
           $yourElement.removeClass('is-dragover');
      }
  })
4
sofarsoghood

このクロスブラウザかどうかはわかりませんが、Chromeでテストし、問題を解決しました。

ページ全体にファイルをドラッグアンドドロップしたいのですが、子要素の上にドラッグすると、私のdragleaveが起動します。私の修正は、マウスのxとyを調べることでした。

ページが読み込まれると、ページ全体をオーバーレイするdivがあります。

ドキュメントの上にドラッグすると表示され、親にドロップするとそれが処理され、親を離れるとxとyがチェックされます。

$('#draganddrop-wrapper').hide();

$(document).bind('dragenter', function(event) {
    $('#draganddrop-wrapper').fadeIn(500);
    return false;
});

$("#draganddrop-wrapper").bind('dragover', function(event) {
    return false;
}).bind('dragleave', function(event) {
    if( window.event.pageX == 0 || window.event.pageY == 0 ) {
        $(this).fadeOut(500);
        return false;
    }
}).bind('drop', function(event) {
    handleDrop(event);

    $(this).fadeOut(500);
    return false;
});
4
chrisallick

私は同じ問題を抱えていて、pk7sソリューションを使用しようとしました。それは機能しましたが、余分なdom要素なしで少し良くすることができました。

基本的に考え方は同じです-ドロップ可能な領域に余分な不可視オーバーレイを追加します。余分なdom要素なしでこれを行うことができます。以下は、CSS疑似要素が登場する部分です。

Javascript

var dragOver = function (e) {
    e.preventDefault();
    this.classList.add('overlay');
};

var dragLeave = function (e) {
    this.classList.remove('overlay');
};


var dragDrop = function (e) {
    this.classList.remove('overlay');
    window.alert('Dropped');
};

var dropArea = document.getElementById('box');

dropArea.addEventListener('dragover', dragOver, false);
dropArea.addEventListener('dragleave', dragLeave, false);
dropArea.addEventListener('drop', dragDrop, false);

CSS

このafterルールは、ドロップ可能な領域の完全に覆われたオーバーレイを作成します。

#box.overlay:after {
    content:'';
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    z-index: 1;
}

完全なソリューションは次のとおりです。 http://jsfiddle.net/F6GDq/8/

同じ問題を抱えている人に役立つことを願っています。

4
rasmusx

非常に簡単なソリューション:

parent.addEventListener('dragleave', function(evt) {
    if (!parent.contains(evt.relatedTarget)) {
        // Here it is only dragleave on the parent
    }
}
4
Owen M

私は同じ問題に出くわしましたが、ここに私の解決策があります-それは上記よりはるかに簡単だと思います。クロスブラウザかどうかはわかりません(バブルの順序に依存する場合があります)

簡単にするためにjQueryを使用しますが、ソリューションはフレームワークに依存しない必要があります。

イベントは、与えられたいずれかの方法で親にバブルします:

<div class="parent">Parent <span>Child</span></div>

イベントを添付します

el = $('.parent')
setHover = function(){ el.addClass('hovered') }
onEnter  = function(){ setTimeout(setHover, 1) }
onLeave  = function(){ el.removeClass('hovered') } 
$('.parent').bind('dragenter', onEnter).bind('dragleave', onLeave)

そしてそれはそれについてです。 :)これは、子のonEnterが親のonLeaveの前に起動しても、順序をわずかに逆にするので、クラスが最初に削除され、ミリ秒後に再実行されるため、動作します。

3

別の実用的なソリューション、もう少しシンプル。

//Note: Due to a bug with Chrome the 'dragleave' event is fired when hovering the dropzone, then
//      we must check the mouse coordinates to be sure that the event was fired only when 
//      leaving the window.
//Facts:
//  - [Firefox/IE] e.originalEvent.clientX < 0 when the mouse is outside the window
//  - [Firefox/IE] e.originalEvent.clientY < 0 when the mouse is outside the window
//  - [Chrome/Opera] e.originalEvent.clientX == 0 when the mouse is outside the window
//  - [Chrome/Opera] e.originalEvent.clientY == 0 when the mouse is outside the window
//  - [Opera(12.14)] e.originalEvent.clientX and e.originalEvent.clientY never get
//                   zeroed if the mouse leaves the windows too quickly.
if (e.originalEvent.clientX <= 0 || e.originalEvent.clientY <= 0) {
2
Profet

イベントが各ドラッグ要素に個別にアタッチされていると仮定すると、これまでのところ、このかなり単純なソリューションは機能しています。

if (evt.currentTarget.contains(evt.relatedTarget)) {
  return;
}
2
Kenneth Spencer

非常に多くの時間を費やした後、私はその提案が意図したとおりに機能するようになりました。ファイルがドラッグされ、ドキュメントがドラッグオーバーされたときにのみ、キューを提供したかったため、Chromeブラウザーでdragleaveが痛みを伴うちらつきを引き起こしていました。

これは私がそれを解決した方法であり、またユーザーに適切な合図を投げます。

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

drip-drop というドラッグアンドドロップモジュールを作成しました。このモジュールは、この奇妙な動作などを修正します。あらゆるものの基礎として使用できる低レベルの優れたドラッグアンドドロップモジュールを探している場合(ファイルのアップロード、アプリ内のドラッグアンドドロップ、外部ソースからの、または外部ソースへのドラッグ)、これをチェックする必要がありますモジュール出力:

https://github.com/fresheneesz/drip-drop

これは、ドリップドロップでしようとしていることを行う方法です。

$('#drop').each(function(node) {
  dripDrop.drop(node, {
    enter: function() {
      $(node).addClass('red')  
    },
    leave: function() {
      $(node).removeClass('red')
    }
  })
})
$('#drag').each(function(node) {
  dripDrop.drag(node, {
    start: function(setData) {
      setData("text", "test") // if you're gonna do text, just do 'text' so its compatible with IE's awful and restrictive API
      return "copy"
    },
    leave: function() {
      $(node).removeClass('red')
    }
  })
})

ライブラリなしでこれを行うには、カウンターテクニックをドリップドロップで使用します。最高評価の回答では、最初のドロップ以外のすべての要素が壊れる重要なステップがありません。適切に行う方法は次のとおりです。

var counter = 0;    
$('#drop').bind({
    dragenter: function(ev) {
        ev.preventDefault()
        counter++
        if(counter === 1) {
          $(this).addClass('red')
        }
    },

    dragleave: function() {
        counter--
        if (counter === 0) { 
            $(this).removeClass('red');
        }
    },
    drop: function() {
        counter = 0 // reset because a dragleave won't happen in this case
    }
});
2
B T

dragleave」イベントは、マウスポインターがターゲットコンテナーのドラッグ領域を出ると発生します。

多くの場合、親だけがdroppableであり、子孫ではないため、これは非常に理にかなっています。 event.stopPropogation()はこのケースを処理すべきだったと思いますが、トリックを実行していないようです。

上記のいくつかのソリューションはほとんどの場合に機能するようですが、dragenter/dragleaveイベント(iframeなど)。

1つの回避策は、event.relatedTargetを確認し、コンテナ内に存在するかどうかを確認してから、dragleaveここで行ったイベント:

function isAncestor(node, target) {
    if (node === target) return false;
    while(node.parentNode) {
        if (node.parentNode === target)
            return true;
        node=node.parentNode;
    }
    return false;
}

var container = document.getElementById("dropbox");
container.addEventListener("dragenter", function() {
    container.classList.add("dragging");
});

container.addEventListener("dragleave", function(e) {
    if (!isAncestor(e.relatedTarget, container))
        container.classList.remove("dragging");
});

動作するフィドルを見つけることができます こちら

1
Lalit Nankani

同様の問題がありました。GoogleChromeでドロップゾーンがちらつく子要素をホバリングすると、bodyのdragleaveイベントでドロップゾーンを非表示にするためのコードが断続的に発生しました。

ドロップゾーンをすぐに呼び出すのではなく、非表示にする機能をスケジュールすることでこれを解決できました。その後、別のdragoverまたはdragleaveが起動されると、スケジュールされた関数呼び出しはキャンセルされます。

body.addEventListener('dragover', function() {
    clearTimeout(body_dragleave_timeout);
    show_dropzone();
}, false);

body.addEventListener('dragleave', function() {
    clearTimeout(body_dragleave_timeout);
    body_dragleave_timeout = setTimeout(show_upload_form, 100);
}, false);

dropzone.addEventListener('dragover', function(event) {
    event.preventDefault();
    dropzone.addClass("hover");
}, false);

dropzone.addEventListener('dragleave', function(event) {
    dropzone.removeClass("hover");
}, false);
1
Arseny

transitioningフラグでタイムアウトを使用し、上部の要素でリッスンできます。子イベントからのdragenter/dragleaveは、コンテナにバブルアップします。

子要素のdragenterがコンテナのdragleaveの前に起動するため、フラグショーを1ミリ秒間遷移するように設定します... dragleaveリスナーは1ミリ秒が始まる前にフラグをチェックしますアップ。

フラグは、子要素への移行中のみtrueになり、(コンテナの)親要素への移行中はtrueになりません

var $el = $('#drop-container'),
    transitioning = false;

$el.on('dragenter', function(e) {

  // temporarily set the transitioning flag for 1 ms
  transitioning = true;
  setTimeout(function() {
    transitioning = false;
  }, 1);

  $el.toggleClass('dragging', true);

  e.preventDefault();
  e.stopPropagation();
});

// dragleave fires immediately after dragenter, before 1ms timeout
$el.on('dragleave', function(e) {

  // check for transitioning flag to determine if were transitioning to a child element
  // if not transitioning, we are leaving the container element
  if (transitioning === false) {
    $el.toggleClass('dragging', false);
  }

  e.preventDefault();
  e.stopPropagation();
});

// to allow drop event listener to work
$el.on('dragover', function(e) {
  e.preventDefault();
  e.stopPropagation();
});

$el.on('drop', function(e) {
  alert("drop!");
});

jsfiddle: http://jsfiddle.net/ilovett/U7mJj/

0
ilovett

このコードを使用してください http://jsfiddle.net/HU6Mk/258/

$('#drop').bind({
         dragenter: function() {
             $(this).addClass('red');
         },

         dragleave: function(event) {
             var x = event.clientX, y = event.clientY,
                 elementMouseIsOver = document.elementFromPoint(x, y);
             if(!$(elementMouseIsOver).closest('.red').length) {
                 $(this).removeClass('red');
             }
        }
    });
0
Mohammad Rezaei

イベントのタイミングに基づいた別のアプローチを次に示します。

子要素からディスパッチされたdragenterイベントは、親要素によってキャプチャでき、常にdragleaveの前に発生します。これらの2つのイベント間のタイミングは非常に短く、考えられる人間のマウスのアクションよりも短くなっています。したがって、アイデアは、dragenterが発生する時間を記憶し、「あまり速くない」後に発生するdragleaveイベントをフィルタリングすることです。

この短い例は、ChromeおよびFirefoxで機能します。

var node = document.getElementById('someNodeId'),
    on   = function(elem, evt, fn) { elem.addEventListener(evt, fn, false) },
    time = 0;

on(node, 'dragenter', function(e) {
    e.preventDefault();
    time = (new Date).getTime();
    // Drag start
})

on(node, 'dragleave', function(e) {
    e.preventDefault();
    if ((new Date).getTime() - time > 5) {
         // Drag end
    }
})
0
smrtl

ドラッグターゲットのすべての子オブジェクトのポインターイベントを削除する必要があります。

function disableChildPointerEvents(targetObj) {
        var cList = parentObj.childNodes
        for (i = 0; i < cList.length; ++i) {
            try{
                cList[i].style.pointerEvents = 'none'
                if (cList[i].hasChildNodes()) disableChildPointerEvents(cList[i])
            } catch (err) {
                //
            }
        }
    }
0
EddieB

Event.eventPhaseを使用してみてください。ターゲットが入力されていない場合にのみ2(Event.AT_TARGET)に設定され、そうでない場合は3(Event.BUBBLING_PHASE)に設定されます。

EventPhaseを使用してdragleaveイベントをバインドまたはバインド解除しました。

$('.dropzone').on('dragenter', function(e) {

  if(e.eventPhase === Event.AT_TARGET) {

    $('.dropzone').addClass('drag-over');

    $('.dropzone').on('dragleave', function(e) {
      $('.dropzone').removeClass('drag-over');
    });

  }else{

    $('.dropzone').off('dragleave');

  }
})

グイド

0
GNaruhn

@azlarの答えに似ているがよりエレガントなソリューションを見つけました。これが私のソリューションです。

$(document).on({
    dragenter: function(e) {
        e.stopPropagation();
        e.preventDefault();
        $("#dragging").show();
    },
    dragover: function(e) {
        e.stopPropagation();
        e.preventDefault();
    },
    dragleave: function(e) {
        e.stopPropagation();
        e.preventDefault();
        if (e.clientX <= 0 ||
            // compare clientX with the width of browser viewport
            e.clientX >= $(window).width() ||
            e.clientY <= 0 ||
            e.clientY >= $(window).height())
            $("#dragging").hide();
    }
});

このメソッドは、マウスがページを離れたかどうかを検出します。 ChromeおよびEdgeでうまく機能します。

0
zysite

pimvdb ..

dragleaveの代わりにdropを使用してみませんか。それは私のために働いた。これで問題が解決することを願っています。

JsFiddleを確認してください: http://jsfiddle.net/HU6Mk/118/

$('#drop').bind({
                 dragenter: function() {
                     $(this).addClass('red');
                 },

                 drop: function() {
                     $(this).removeClass('red');
                 }
                });

$('#drag').bind({
                 dragstart: function(e) {
                     e.allowedEffect = "copy";
                     e.setData("text/plain", "test");
                 }
                });
0
abhi