2013-01-07 65 views
6

我試圖跟蹤的dragenter /離開整個屏幕,這是迄今爲止在Chrome/Safari瀏覽器,從https://stackoverflow.com/a/10310815/698289的draghover插件的禮貌在工作正常時:火狐射擊dragleave拖動文本上

$.fn.draghover = function(options) { 
    return this.each(function() { 

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

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

     self.on('dragleave drop', function(e) { 
      // timeout is needed because Firefox 3.6 fires the dragleave event on 
      // the previous element before firing dragenter on the next one 
      setTimeout(function() { 
       collection = collection.not(e.target); 
       if (collection.size() === 0) { 
        self.trigger('draghoverend'); 
       } 
      }, 1); 
     }); 
    }); 
}; 

function setText(text) { 
    $('p.target').text(text); 
} 

$(document).ready(function() { 
    $(window).draghover().on({ 
     'draghoverstart': function() { 
      setText('enter'); 
     }, 
     'draghoverend': function() { 
      setText('leave'); 
     } 
    }); 
}); 

但是火狐仍然給我的問題,當我拖過文本項目,這裏有一個小提琴證明:http://jsfiddle.net/tusRy/6/

這是一個Firefox的錯誤或可在此與JS被馴服?還是有更強大的方法來執行所有這些?

謝謝!

UPDATE:將小提琴更新爲http://jsfiddle.net/tusRy/6/以減少混亂。解釋小提琴的預期行爲:

  • 將一個文件拖到窗口中,並且p.target應該是「ENTER」彩色黃色。
  • 將一個文件拖出窗口,p.target應該是「LEAVE」紅色。
  • 在窗口中放置一個文件,並且p.target應該是「LEAVE」紅色。

在firefox中,當您將文件拖動到文本上時,會觸發LEAVE事件。

+0

我已經通過使用覆蓋div來解決這個問題,按照http://jsfiddle.net/tusRy/7/但是我並不真的很高興這是解決方案,所以我會離開這個問題打開直到有更好的想法出現。 – DanH

回答

1

我想出了一種解決方案,但尚未在Chrome和FF以外的其他瀏覽器上進行測試,但工作到目前爲止。這是setTimeout現在的樣子:

setTimeout(function() { 
    var isChild = false; 

    // in order to get permission errors, use the try-catch 
    // to check if the relatedTarget is a child of the body 
    try { 
     isChild = $('body').find(e.relatedTarget).length ? true : isChild; 
    } 
    catch(err){} // do nothing 

    collection = collection.not(e.target); 
    if (collection.size() === 0 && !isChild) { 
     self.trigger('draghoverend'); 
    } 
}, 1); 

整個這裏的代碼 - http://jsfiddle.net/tusRy/13/

這個想法是檢查相關標記是否是身體的孩子,在這種情況下,我們仍然在瀏覽器中,並且應該不觸發事件。由於這會在移出窗口時拋出錯誤,我使用了一種嘗試方法來避免它。

好吧,也許與JS更多的技能有人能改善這個:)

8

由於火狐22.0仍然是這樣做的版本。當您拖動文本節點時,會觸發兩種事件:一種是事件目標和relatedTarget是文本節點的父元素,另一種是目標是父元素,另一種是relatedTarget是實際文本節點(甚至沒有適當的DOM元素)。

的解決方法就是在你的dragenterdragleave處理程序來檢查這兩種類型的事件,而忽略他們:

try { 
    if(event.relatedTarget.nodeType == 3) return; 
} catch(err) {} 
if(event.target === event.relatedTarget) return; 

我使用try/catch塊,檢查節點類型,因爲偶然事件引發(莫名)(例如,在其他iframe中)並試圖訪問它們的nodeType會引發權限錯誤。

這裏的實現: http://jsfiddle.net/9A7te/

+1

我認爲jQuery-2.1.1的dragenter和dragleave事件處理存在一個問題:我注意到,不是將有問題的文本節點報告爲dragenter和dragleave上的event.target,而是通過文本節點的父元素。如果你仍然注意到問題,我想知道是否在這裏出生可能會有所幫助。 – Gavin

+1

順便說一句,這個答案對我最有幫助。以上情況我的回答並不十分清楚:我的意思是在這個bug中,jQuery本身並不準確地將事件目標複製到它的自定義Event對象中。我已經實現了基於event.originalEvent.target和event.originalEvent.relatedTarget的nodeType檢查,效果很好 – Gavin

+1

完美的工作!我將它添加到插件本身,以避免在最終事件處理程序中重新編寫它。在Chrome和Firefox中運行得非常好。還沒有在其他瀏覽器中測試過驗證任何愚蠢的錯誤,但這些是我必須支持的唯一兩種主要瀏覽器。 – Demonslay335

1

1)您的懸浮窗應該只有一個子元素,這可能會擁有一切你需要的。喜歡的東西

<div id="#dropzone"> 
    <div><!--Your contents here--></div> 
</div> 

2)使用這個CSS:

#dropzone * { pointer-events: none; } 

您可能需要包括自*:before:after並不適用於他們。

這應該足以讓放置在Firefox和Chrome中工作。在你的例子中,它應該足以補充:

body * { pointer-events: none; } 

在CSS的末尾。我在這裏所做的那樣:

其他例子:

1

我找到了答案,在非選擇的答案對這個SO問題詢問dragleave firing on child elements。我有一個<div>有很多孩子的元素。當頁面上有dragenter時,通過<div>可以看到半透明覆蓋<span>。正如你發現的那樣,'dragover'不像mouseover。只要您將鼠標懸停在子元素上,它就會觸發dragleave

解決方案? Dragout它使得dragover的工作更像mouseover。很短。