36

Firefoxは、ウィンドウの外側にドラッグすると、dragleaveイベントを適切にトリガーしません。

https://bugzilla.mozilla.org/show_bug.cgi?id=665704

https://bugzilla.mozilla.org/show_bug.cgi?id=656164

私はこれの回避策を開発しようとしています(Gmailがそれを行っているので可能だと私は知っています)が、私が思いつくことができる唯一のことは本当にハックなようです。

dragoverウィンドウの外側にドラッグするタイミングを知る1つの方法は、イベントの発生が停止するのを待つことです(dragoverドラッグアンドドロップ操作中に常に発生するため)。これが私がそれをしている方法です:

var timeout;

function dragleaveFunctionality() {
  // do stuff
}

function firefoxTimeoutHack() {
  clearTimeout(timeout);
  timeout = setTimeout(dragleaveFunctionality, 200);
}

$(document).on('dragover', firefoxTimeoutHack);

このコードは基本的に、タイムアウトを何度も作成してクリアしています。dragoverイベントの発生が停止しない限り、200ミリ秒のタイムアウトには達しません。

これは機能しますが、この目的でタイムアウトを使用するというアイデアは好きではありません。気分が悪い。また、「ドロップゾーン」スタイルがなくなるまでにわずかな遅れがあることも意味します。

私が持っていたもう1つのアイデアは、マウスがウィンドウから離れるタイミングを検出することでしたが、ドラッグアンドドロップ操作では通常の方法では機能しないようです。

誰かがこれを行うためのより良い方法を持っていますか?

アップデート:

これが私が使用しているコードです:

 $(function() {
          var counter = 0;
          $(document).on('dragenter', function(e) {
            counter += 1;
            console.log(counter, e.target);
          });
          $(document).on('dragleave', function(e) {
            counter -= 1;
            console.log(counter, e.target);
          });
        });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Open up the console and look at what number is reporting when dragging files in and out of the window. The number should always be 0 when leaving the window, but in Firefox it's not.</p>

4

5 に答える 5

58

私は解決策を見つけました。問題は、dragleaveイベントが発生しないということではありませんでした。むしろ、dragenter最初にファイルをウィンドウにドラッグしたとき (さらに、特定の要素をドラッグしたとき) に、イベントが 2 回発生していました。私の最初の解決策は、最後のイベントがいつ発生したかを追跡するためにカウンターを使用することでしたdragleaveが、イベントの二重dragenter起動によりカウントが台無しになりました。(なぜ私はdragleaveあなたの質問を聞くことができなかったのですか?要素を離れるときだけでなく、子要素に入るときにも起動するという点で とdragleave非常によく似た機能を持っているためです。したがって、起動するとき、マウスはまだその中にある可能性があります。元の要素の境界。)mouseoutdragleave

私が思いついた解決策は、どの要素dragenterdragleaveがトリガーされたかを追跡することでした。イベントはドキュメントまで伝播するため、特定の要素をリッスンするdragenterdragleave、その要素のイベントだけでなく、その子のイベントもキャプチャされます。

$()そこで、どの要素でどのイベントが発生したかを追跡するための jQuery コレクションを作成しました。dragenter が発生するたびに をコレクションに追加し、 dragleave が発生するたびにコレクションからevent.target削除event.targetしました。コレクションが空の場合、実際には元の要素を残したということになります。代わりに子要素を入力すると、少なくとも 1 つの要素 (子) がまだ jQuery コレクションに残っているからです。最後に、イベントが発生したときにコレクションを空にリセットして、次のイベントが発生dropしたときにすぐに使えるようにします。dragenter

また、jQuery は自動的に重複チェックを行うため、余分な作業を大幅に節約event.targetできます。Firefox が誤ってdragenter.

とにかく、これが私が最終的に使用したコードの基本バージョンです。他の誰かがそれを使用することに興味がある場合は、単純な jQuery プラグインに入れました。基本的に、.draghover任意の要素を呼び出し、要素draghoverstartに最初にドラッグしたときにトリガーされdraghoverend、ドラッグが実際に要素を離れるとトリガーされます。

// The plugin code
$.fn.draghover = function(options) {
  return this.each(function() {

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

    self.on('dragenter', function(e) {
      if (collection.length === 0) {
        self.trigger('draghoverstart');
      }
      collection = collection.add(e.target);
    });

    self.on('dragleave drop', function(e) {
      collection = collection.not(e.target);
      if (collection.length === 0) {
        self.trigger('draghoverend');
      }
    });
  });
};

// Now that we have a plugin, we can listen for the new events 
$(window).draghover().on({
  'draghoverstart': function() {
    console.log('A file has been dragged into the window.');
  },
  'draghoverend': function() {
    console.log('A file has been dragged out of window.');
  }
});

jQueryなし

jQuery を使用せずにこれを処理するには、次のようにします。

// I want to handle drag leaving on the document
let count = 0
onDragEnter = (event) => {
  if (event.currentTarget === document) {
    count += 1
  }
}

onDragLeave = (event) => {
  if (event.currentTarget === document) {
     count += 0
  }

  if (count === 0) {
    // Handle drag leave.
  }
}
于 2012-04-25T07:00:57.410 に答える
3

達成したいことに応じて:-moz-drag-over、Firefox でのみ利用可能な疑似クラスを使用してこの問題を回避できます。これにより、要素上にドラッグされたファイルに反応することができます。

この簡単なデモを見てみましょうhttp://codepen.io/ryanseddon/pen/Ccsua

.dragover {
    background: red;
    width: 500px;
    height: 300px;
}
.dragover:-moz-drag-over {
    background: green;
}
于 2013-04-02T03:23:04.880 に答える
0

@PhilipWalton のコードに触発されて、jQuery プラグイン コードを簡略化しました。

$.fn.draghover = function(fnIn, fnOut) {
    return this.each(function() {
        var n = 0;
        $(this).on('dragenter', function(e) {
            (++n, n==1) && fnIn && fnIn.call(this, e);
        }).on('dragleave drop', function(e) {
            (--n, n==0) && fnOut && fnOut.call(this, e);
        });
    });
};

jquery hover メソッドのような jquery プラグインを使用できるようになりました。

// Testing code 1
$(window).draghover(function() {
    console.log('into window');
}, function() {
    console.log('out of window');
});

// Testing code 2
$('#d1').draghover(function() {
    console.log('into #d1');
}, function() {
    console.log('out of #d1');
});
于 2015-04-22T20:58:42.307 に答える
0

私のために働いて、私に数回かかった唯一の解決策は、これが誰かを助けることを願っています!

クローンを作成するときは、イベントとデータを使用してディープクローンする必要があることに注意してください。

HTML:

<div class="dropbox"><p>Child element still works!</p></div>

<div class="dropbox"></div>

<div class="dropbox"></div>

jQuery

$('.dropbox').each(function(idx, el){
    $(this).data("counter" , 0);
});

$('.dropbox').clone(true,true).appendTo($('body');

$('dropbox').on({
    dragenter : function(e){
        $(this).data().counter++;
        <!-- YOUR CODE HERE -->
    },
      dragleave: function(e){

        $(this).data().counter--;

         if($(this).data().counter === 0)
              <!-- THEN RUN YOUR CODE HERE -->
    }
});
于 2015-07-27T12:44:43.150 に答える
-1
addEvent(document, "mouseout", function(e) {
    e = e ? e : window.event;
    var from = e.relatedTarget || e.toElement;
    if (!from || from.nodeName == "HTML") {
        // stop your drag event here
        // for now we can just use an alert
        alert("left window");
    }
});

これは、マウスがウィンドウから離れたことをどのように検出できますか?からコピーされたものです。. addEvent は単なるクロスブラウザの addEventListener です。

于 2012-04-23T00:34:37.990 に答える