web-dev-qa-db-ja.com

ウィンドウの外にドラッグするときにFirefoxでdragleaveイベントを検出する方法

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

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

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

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

ウィンドウの外側にドラッグしたことを知る1つの方法は、dragoverイベントが発生を停止するのを待つことです(ドラッグアンドドロップ操作中に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>
36
Philip Walton

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

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

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

jQueryは、重複チェックを自動的に行うため、多くの余分な作業も節約できます。そのため、Firefoxが誤ってdragenterをダブル呼び出しした場合でも、event.targetが2回追加されることはありません。

とにかく、これが私が最終的に使用したコードの基本バージョンです。他の誰かがそれを使用することに興味があるなら、私はそれを単純な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.');
  }
});
57
Philip Walton

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

この簡単なデモを見てください http://codepen.io/ryanseddon/pen/Ccsua

.dragover {
    background: red;
    width: 500px;
    height: 300px;
}
.dragover:-moz-drag-over {
    background: green;
}
3
Ryan Seddon

@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ホバーメソッドのような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');
});
0
cuixiping

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

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

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 -->
    }
});
0
Bass
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です。

0
pbfy0