HTML5 ड्रैगवेलवे को बाल तत्व को मँडराते समय निकाल दिया गया


300

मेरे पास जो समस्या है वह यह है कि 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>

निम्नलिखित जावास्क्रिप्ट के साथ:

$('#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 अपडेट: टीएल; डीआर, सीएसएस देखें pointer-events: none;जैसा कि आधुनिक ब्राउज़रों और आईई 11 में काम करने वाले @ एचडी के जवाब में नीचे वर्णित है।


बग पिम्पवड ने मई 2012 के अनुसार वेबकिट में अभी भी मौजूद होने की सूचना दी है। मैंने इसे ड्रैगओवर में एक वर्ग जोड़कर भी काउंटर किया है, जो कहीं भी अच्छा नहीं है क्योंकि यह इतनी बार आग लगाता है, लेकिन इस मुद्दे को थोड़ा पैच करता है।
अंजाम

2
@ काजम: धन्यवाद, जो एक हद तक काम करता है। हालांकि, क्रोम पर, बच्चे के तत्व को दर्ज करने या छोड़ने के दौरान एक फ्लैश होता है, संभवतः क्योंकि dragleaveउस मामले में अभी भी निकाल दिया गया है।
११:०२

मैंने एक jQuery यूआई बग अपवोट खोला है तो वे उस पर संसाधनों डाल करने के लिए तय कर सकते हैं स्वागत है
fguillen

@fguillen: मुझे क्षमा करें, लेकिन इसका jQuery UI से कोई लेना-देना नहीं है। वास्तव में, jQuery को बग को ट्रिगर करने की आवश्यकता नहीं है। मैंने पहले से ही एक WebKit बग दर्ज कर लिया है, लेकिन अब तक कोई अपडेट नहीं है।
pimvdb

2
@pimvdb आप HD के उत्तर को स्वीकार क्यों नहीं करते?
TylerH

जवाबों:


337

आपको बस एक रेफ़रेंस काउंटर रखने की ज़रूरत है, जब आप ड्रैगेंटर प्राप्त करते हैं, तो आप इसे बढ़ाते हैं, जब आप ड्रैगवैलव प्राप्त करते हैं। जब काउंटर 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');
        }
    }
});

नोट: ड्रॉप ईवेंट में, काउंटर को शून्य पर रीसेट करें, और जोड़े गए वर्ग को साफ़ करें।

आप इसे यहां चला सकते हैं


8
OMG यह सबसे स्पष्ट समाधान है और केवल एक वोट था ... लोगों पर आओ, आप बेहतर कर सकते हैं। मैं इसके बारे में सोच रहा था लेकिन पहले कुछ उत्तरों के परिष्कार के स्तर को देखने के बाद मैंने इसे लगभग छोड़ दिया। क्या आपको कोई कमियां थीं?
आर्थर कोरेंजन

11
यह तब काम नहीं आया जब घसीटा जा रहा तत्व का किनारा दूसरे ड्रैग करने योग्य तत्व के किनारे को छूता है। उदाहरण के लिए एक छांटने योग्य सूची; तत्व को नीचे की ओर खींचते हुए, अगली ड्रैग करने योग्य वस्तु के ऊपर काउंटर 0 पर वापस नहीं आता है, इसके बजाय यह 1 पर अटक जाता है। लेकिन अगर मैं इसे बग़ल में खींचता हूं, तो किसी अन्य ड्रैग करने योग्य तत्व से बाहर, यह काम करता है। मैं pointer-events: noneबच्चों के साथ चला गया । जब मैं ड्रैग करना शुरू करता हूं तो मैं उस क्लास को जोड़ता हूं जिसमें यह प्रॉपर्टी होती है, जब ड्रैग ओवर मैं क्लास को हटा देता हूं। सफारी और क्रोम पर अच्छी तरह से काम किया, लेकिन फ़ायरफ़ॉक्स पर नहीं।
आर्थर कोर्जेन

13
यह मेरे लिए सभी ब्राउज़रों में काम करता था, लेकिन फ़ायरफ़ॉक्स। मेरे पास एक नया समाधान है जो मेरे मामले में हर जगह काम करता है। सबसे पहले dragenterमैं event.currentTargetएक नए चर में बचत करता हूं dragEnterTarget। जब तक dragEnterTargetसेट किया जाता है, मैं आगे की dragenterघटनाओं को अनदेखा करता हूं , क्योंकि वे बच्चों से हैं। सभी dragleaveघटनाओं में मैं जाँच करता हूँ dragEnterTarget === event.target। यदि यह गलत है तो घटना को नजरअंदाज कर दिया जाएगा क्योंकि यह एक बच्चे द्वारा निकाल दिया गया था। अगर यह सच है तो मैं रीसेट dragEnterTargetकर देता हूं undefined
पिपो

3
महान समाधान। मुझे उस फ़ंक्शन में 0 से काउंटर को रीसेट करने की आवश्यकता थी जो ड्रॉप को स्वीकार करने के लिए संभालती है, अन्यथा बाद के ड्रग्स ने अपेक्षा के अनुरूप काम नहीं किया।
लियाम जॉनसन

2
@ मुझे अपनी टिप्पणी यहाँ टिप्पणियों की विशाल सूची में दिखाई नहीं दी, लेकिन हाँ, यह ठीक है। क्यों नहीं अपने जवाब में शामिल करें?
बीटी

93

क्या बाल तत्व में घसीटते समय ड्रैगवैल को गोलीबारी से रोकना संभव है?

हाँ।

#drop * {pointer-events: none;}

क्रोम के लिए सीएसएस पर्याप्त लगता है।

फ़ायरफ़ॉक्स के साथ इसका उपयोग करते समय, # पृष्ठभूमि में सीधे टेक्स्ट नोड्स नहीं होने चाहिए (अन्यथा एक अजीब मुद्दा है जहां एक तत्व "इसे खुद को छोड़ दें" ), इसलिए मैं इसे केवल एक तत्व के साथ छोड़ने का सुझाव देता हूं (उदाहरण के लिए, अंदर एक div का उपयोग करें) # पृष्ठभूमि के अंदर सब कुछ डालने के लिए)

यहाँ मूल प्रश्न (टूटा हुआ) उदाहरण को हल करने वाला jsfiddle है

मैंने @ थियोडोर ब्राउन उदाहरण से कांटा गया एक सरलीकृत संस्करण भी बनाया है , लेकिन केवल इस सीएसएस में आधारित है।

सभी ब्राउज़रों के पास यह सीएसएस लागू नहीं है, हालांकि: http://caniuse.com/pointer-events

फेसबुक स्रोत कोड देखकर मुझे यह pointer-events: none;कई बार मिल सकता है , हालांकि यह संभवतः सुंदर गिरावट के साथ एक साथ उपयोग किया जाता है। कम से कम यह बहुत सरल है और बहुत सारे वातावरण के लिए समस्या को हल करता है।


पॉइंटर-ईवेंट प्रॉपर्टी आगे बढ़ने वाला सही समाधान है, लेकिन दुर्भाग्य से यह IE8-IE10 में काम नहीं करता है, जो अभी भी व्यापक रूप से उपयोग किए जाते हैं। इसके अलावा, मुझे यह इंगित करना चाहिए कि IE11 में आपका वर्तमान jsFiddle भी काम नहीं करता है, क्योंकि यह आवश्यक घटना श्रोताओं और डिफ़ॉल्ट रूप से रोकथाम को नहीं जोड़ता है।
थियोडोर ब्राउन

2
सूचक-घटनाओं का उपयोग करना वास्तव में एक अच्छा जवाब है, मैंने खुद को पता लगाने से पहले थोड़ा संघर्ष किया, यह उत्तर अधिक होना चाहिए।
फ्लोरीबॉन

हम में से उन लोगों के लिए शानदार विकल्प जो पुराने ब्राउज़रों का समर्थन नहीं करते हैं।
ल्यूक हैनफोर्ड

7
यदि आपके बच्चे एक बटन हैं तो क्या होगा? ऊ
डेविड

9
यह केवल तभी काम करता है जब आपके पास क्षेत्र के अन्य नियंत्रक तत्व (संपादित करें, हटाएं) न हों, क्योंकि यह समाधान उन्हें भी अवरुद्ध करता है ..
Zoltán Süle

45

यहां, सबसे सरल क्रॉस-ब्राउज़र समाधान (गंभीरता से):

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

कुछ शब्दों में, आप ड्रॉपज़ोन के अंदर एक "मुखौटा" बनाते हैं, जिसमें चौड़ाई और ऊँचाई विरासत में मिली होती है, स्थिति निरपेक्ष होती है, जो ड्रैगओवर शुरू होने पर बस दिखाई देगी।
तो, उस मास्क को दिखाने के बाद, आप दूसरों को ड्रैगवेलव और उस पर ईवेंट ड्रॉप करके ट्रिक कर सकते हैं।

छोड़ने या छोड़ने के बाद, आप बस मास्क को फिर से छिपाते हैं।
सरल और जटिलताओं के बिना।

(अवलोकन करें: ग्रेग पेटिट सलाह - आपको यह सुनिश्चित करना चाहिए कि मास्क पूरे बॉर्डर पर मंडराता है,)


यकीन नहीं क्यों, लेकिन यह क्रोम के साथ लगातार काम नहीं कर रहा है। कभी-कभी क्षेत्र छोड़ने से मुखौटा दिखाई देता है।
ग्रेग पेटिट

2
दरअसल, यह सीमा है। मास्क को बॉर्डर को ओवरलैप करने के साथ, अपनी खुद की कोई सीमा नहीं है, और इसे ठीक काम करना चाहिए।
ग्रेग पेटिट

1
ध्यान दें, आपके jsfiddle में एक बग है, ड्रैग_ड्रॉब में, आपको "# बॉक्स" नहीं "# बॉक्स-ए" पर हॉवर क्लास को हटा देना चाहिए
एंट्रॉपी

यह एक अच्छा समाधान है, लेकिन किसी तरह यह मेरे लिए काम नहीं किया। मैं अंत में एक वर्कअराउंड का पता लगाता हूं। आप में से उन लोगों के लिए जो कुछ और ढूंढ रहे हैं। आप यह कोशिश कर सकते हैं: github.com/bingjie2680/jquery-draghover
bingjie2680

नहीं, मैं बाल तत्वों पर नियंत्रण नहीं खोना चाहता। मैंने एक सरल jQuery प्लगइन बनाया है जो हमारे लिए काम करने में समस्या से संबंधित है। मेरा उत्तर जांचें
लुका फागियोली

39

यह प्रश्न पूछे जाने के बाद काफी समय हो गया है और बहुत सारे समाधान (बदसूरत हैक्स सहित) प्रदान किए गए हैं।

मैं उसी समस्या को ठीक करने में कामयाब रहा जिसका मैंने हाल ही में इस उत्तर में उत्तर के लिए धन्यवाद किया था और सोचा कि यह किसी के लिए उपयोगी हो सकता है जो इस पृष्ठ पर आता है। संपूर्ण विचार यह है evenet.targetकि ondrageenterहर उस समय इसे किसी भी अभिभावक या बच्चे के तत्वों में संग्रहीत किया जाए । फिर ondragleaveजांच करें कि क्या वर्तमान लक्ष्य ( event.target) आपके द्वारा संग्रहित वस्तु के बराबर हैondragenter

इन दोनों का मिलान केवल तभी होता है जब आपका ड्रैग ब्राउज़र विंडो को छोड़ रहा हो।

कारण यह है कि यह ठीक काम करता है जब माउस एक तत्व (कहता है el1) को छोड़ता है और किसी अन्य तत्व (कहते हैं el2) में प्रवेश करता है , तो पहले el2.ondragenterकहा जाता है और फिर el1.ondragleave। केवल जब खींचें जा रहा है / ब्राउज़र विंडो में प्रवेश, event.targetहो जाएगा ''दोनों में el2.ondragenter और el1.ondragleave

यहाँ मेरा काम का नमूना है। मैंने इसे IE9 +, क्रोम, फ़ायरफ़ॉक्स और सफारी पर परीक्षण किया है।

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

उचित स्टाइल के साथ मैंने जो कुछ भी किया है वह इनर डिव (# फाइल-ड्रॉप-एरिया) बनाने के लिए है जब भी किसी फाइल को स्क्रीन में घसीटा जाता है ताकि उपयोगकर्ता फाइलों को आसानी से उचित जगह पर गिरा सके।


4
यह सबसे अच्छा समाधान है, यह काउंटर से बेहतर है (विशेषकर यदि आप घटनाओं को सौंपते हैं) और यह ड्रैगेबल बच्चों के साथ भी काम करता है।
फ्रेड

3
यह डुप्लिकेट ड्रैगेंटर घटनाओं की समस्या के लिए थियो की मदद नहीं करता है
बीटी

क्या यह "बच्चों" के लिए काम करता है जो सीएसएस छद्म तत्व या छद्म वर्ग हैं? मैं इसे प्राप्त नहीं कर सका, लेकिन शायद मैं इसे गलत कर रहा था।
जोश बलेकर स्नाइडर

1
मार्च 2020 तक मुझे इस समाधान के साथ सबसे अच्छी किस्मत मिली है। नोट: कुछ लिंटर ==ओवर के उपयोग के बारे में शिकायत कर सकते हैं ===। आप ईवेंट लक्ष्य ऑब्जेक्ट संदर्भों की तुलना कर रहे हैं, इसलिए ===ठीक भी काम करता है।
एलेक्स

33

इस मुद्दे को हल करने का "सही" तरीका ड्रॉप टारगेट के बच्चे तत्वों पर सूचक घटनाओं को अक्षम करना है (जैसा कि @ HD के उत्तर में)। यहाँ एक jsField मैंने बनाया है जो इस तकनीक को प्रदर्शित करता है । दुर्भाग्य से, यह IE11 से पहले इंटरनेट एक्सप्लोरर के संस्करणों में काम नहीं करता है, क्योंकि वे सूचक घटनाओं का समर्थन नहीं करते थे

सौभाग्य से, मैं एक वर्कअराउंड के साथ आने में सक्षम था जो IE के पुराने संस्करणों में काम करता है । मूल रूप से, इसमें उन dragleaveघटनाओं की पहचान करना और उनकी अनदेखी करना शामिल है जो बाल तत्वों पर घसीटते समय घटित होती हैं। क्योंकि dragenterघटना को dragleaveमाता-पिता की घटना से पहले बच्चे के नोड्स पर निकाल दिया जाता है , प्रत्येक बच्चे के नोड में अलग-अलग इवेंट श्रोताओं को जोड़ा जा सकता है जो ड्रॉप लक्ष्य से "इग्नि-ड्रैग-लीव" क्लास को जोड़ते हैं या हटाते हैं। तब ड्रॉप लक्ष्य की dragleaveईवेंट श्रोता केवल उन कॉलों को अनदेखा कर सकती है जो इस वर्ग के मौजूद होने पर होती हैं। यहाँ इस वर्कफ़्लो को प्रदर्शित करने वाला jsFiddle है । यह क्रोम, फ़ायरफ़ॉक्स और IE8 + में परीक्षण और काम कर रहा है।

अपडेट करें:

मैंने फीचर डिटेक्शन का उपयोग करके एक संयुक्त समाधान प्रदर्शित करते हुए एक jsFiddle बनाया , जहां पॉइंटर घटनाओं का उपयोग किया जाता है यदि समर्थित (वर्तमान में क्रोम, फ़ायरफ़ॉक्स, और IE11), और ब्राउज़र पॉइडर इवेंट समर्थन उपलब्ध नहीं होने पर चाइल्ड नोड्स में ईवेंट जोड़ने के लिए वापस आ जाता है (IE8) -10)।


यह उत्तर अवांछनीय फायरिंग के लिए एक समाधान दिखाता है लेकिन सवाल को उपेक्षित करता है "क्या ड्रैगवैलव को बाल तत्व में खींचते समय फायरिंग से रोकना संभव है?" पूरी तरह से।
एचडी

ब्राउज़र के बाहर से फ़ाइल खींचते समय व्यवहार अजीब हो सकता है। फ़ायरफ़ॉक्स में मुझे "प्रवेश करने वाले बच्चे -> प्रवेश करने वाले माता-पिता -> छोड़ने वाले बच्चे -> प्रवेश करने वाले बच्चे -> छोड़ने वाले बच्चे" को माता-पिता को छोड़कर, जो "अति" वर्ग के साथ छोड़ दिया है। पुराने IE को addEventListener के लिए एक संलग्न प्रतिस्थापन की आवश्यकता होगी।
एचडी

यह समाधान बुदबुदाती पर दृढ़ता से निर्भर करता है, सभी addEventListener में "झूठे" को आवश्यक के रूप में जोर दिया जाना चाहिए (हालांकि यह डिफ़ॉल्ट व्यवहार है), क्योंकि बहुत से लोग इस बारे में नहीं जानते होंगे।
एचडी

वह एकमात्र ड्रैगगैबल ड्रॉपजोन में एक प्रभाव जोड़ता है जो तब दिखाई नहीं देता जब ड्रॉपजोन को अन्य ड्रैग करने योग्य ऑब्जेक्ट्स के लिए उपयोग किया जाता है जो ड्रैगस्टार्ट इवेंट को ट्रिगर नहीं करता है। शायद असली ड्रॉपज़ोन को अन्य हैंडलर के साथ रखने के दौरान ड्रैगिंग के प्रभाव के लिए सब कुछ एक ड्रॉपज़ोन के रूप में उपयोग करना होगा।
एचडी

1
@HD मैंने dragleaveक्रोम, फ़ायरफ़ॉक्स और IE11 + में फायरिंग से घटना को रोकने के लिए पॉइंटर-ईवेंट सीएसएस संपत्ति का उपयोग करने के बारे में जानकारी के साथ अपना जवाब अपडेट किया । मैंने IE10 के अलावा IE8 और IE9 का समर्थन करने के लिए अपने अन्य वर्कअराउंड को भी अपडेट किया। यह जानबूझकर है कि ड्रॉपज़ोन प्रभाव केवल तब जोड़ा जाता है जब "मुझे खींचें" लिंक खींच रहा हो। अन्य लोग इस व्यवहार को बदलने के लिए बेझिझक अपने उपयोग मामलों का समर्थन कर सकते हैं।
थियोडोर ब्राउन

14

समस्या यह है कि 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');
               }
           }

1
धन्यवाद! मुझे यह क्रोम में काम करने के लिए नहीं मिल सकता है। क्या आप अपने हैक का काम करने वाला फील प्रदान कर सकते हैं?
pimvdb

3
मैं यह सोच कर भी कर रहा था कि कोर्डर्स की जाँच करके। आपने मेरे लिए अधिकतर काम किया, :)। मुझे हालांकि कुछ समायोजन करने थे:if (e.x >= (rect.left + rect.width) || e.x <= rect.left || e.y >= (rect.top + rect.height) || e.y <= rect.top)
क्रिस्टोफ

यह क्रोम में काम नहीं करेगा क्योंकि यह घटना नहीं है e.xऔर e.y
हेंगजी

मुझे यह समाधान पसंद है। पहले फ़ायरफ़ॉक्स में काम नहीं किया। लेकिन अगर आप e.clientX के साथ ex को बदलते हैं और e.clientY के साथ आंख काम करता है। क्रोम में भी काम करता है।
निकोल स्टुटज़

मेरे लिए क्रोम में काम नहीं किया था, न ही क्रिस या डैनियल स्टट्स ने क्या सुझाव दिया था
टिमो हुओवेनन

14

यदि आप एचटीएमएल 5 का उपयोग कर रहे हैं, तो आप माता-पिता के ग्राहक प्राप्त कर सकते हैं:

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


2
बहुत बढ़िया जवाब।
ब्रोइससेइब

धन्यवाद दोस्त, मैं सादे जावास्क्रिप्ट दृष्टिकोण पसंद है।
टिम गेरहार्ड

जब तत्वों के उपयोग पर border-radius, पॉइंटर को कोने के पास ले जाना वास्तव में तत्व को छोड़ देगा , लेकिन यह कोड अभी भी सोचता है कि हम अंदर हैं (हमने तत्व को छोड़ दिया है लेकिन हम अभी भी आयत में हैं)। तब dragleaveईवेंट हैंडलर को बिल्कुल नहीं बुलाया जाएगा।
जे। दादानिया

11

pointer-eventsसीएसएस संपत्ति का उपयोग करने के लिए एक बहुत ही सरल समाधान है । बस इसके मूल्य को हर चाइल्ड एलिमेंट noneपर ड्रैगस्टार्ट पर सेट करें । ये तत्व अब माउस से संबंधित घटनाओं को ट्रिगर नहीं करेंगे, इसलिए वे माउस को उन पर नहीं पकड़ेंगे और इस तरह से माता-पिता पर ड्रैगलीव को ट्रिगर नहीं करेंगे ।

autoड्रैग खत्म करते समय इस प्रॉपर्टी को वापस सेट करना न भूलें ;)


11

यह काफी सरल समाधान मेरे लिए अब तक काम कर रहा है, यह मानते हुए कि आपकी घटना व्यक्तिगत रूप से प्रत्येक खींचें तत्व से जुड़ी हुई है।

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

यह भी खूब रही! @kenneth को साझा करने के लिए धन्यवाद, आपने मेरा दिन बचाया! बहुत सारे अन्य उत्तर केवल तभी लागू होते हैं जब आपके पास एक एकल ड्रापेबल ज़ोन होता है।
एंटोनी

मेरे लिए, यह क्रोम और फ़ायरफ़ॉक्स में काम करता है, लेकिन आईडी एज में काम नहीं करता है। कृपया देखें: jsfiddle.net/iwiss/t9pv24jo
iwis

8

बहुत ही सरल उपाय:

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

यह सफारी 12.1 में काम करने के लिए प्रतीत नहीं होता है: jsfiddle.net/6d0qc87m
एडम टेलर

7

आप इसे 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');
        }
    }

}

दुर्भाग्य से यह क्रोम में काम नहीं करता है क्योंकि घटनाओं relatedTargetपर मौजूद नहीं है dragleave, और मुझे लगता है कि आप क्रोम में काम कर रहे हैं क्योंकि आपका उदाहरण फ़ायरफ़ॉक्स में काम नहीं करता है। यहां ऊपर दिए गए कोड के साथ एक संस्करण लागू किया गया है।


बहुत बहुत धन्यवाद, लेकिन वास्तव में यह क्रोम है मैं इस समस्या को हल करने की कोशिश कर रहा हूं।
pimvdb

5
@pimvdb मैं देख रहा हूं कि आपने बग को लॉग इन किया है , मैं इस संदर्भ में किसी और के उत्तर में आने के लिए सिर्फ एक संदर्भ छोड़ दूंगा।
रॉबर्ट

मैंने वास्तव में किया था, लेकिन मैं यहां एक लिंक जोड़ना भूल गया। ऐसा करने के लिए धन्यवाद।
pimvdb

क्रोम बग को माध्य समय में तय किया गया है।
phk

7

और यहाँ यह जाता है, क्रोम के लिए एक समाधान:

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

क्या यह «(टाइपो ईवेंट.क्लिएंटएक्स === 'अपरिभाषित') में जाता है»?
अल्दकेन

1
अच्छी तरह से काम किया है, लेकिन ब्राउज़र पर एक और खिड़की हो सकती है, इसलिए माउस स्थान प्राप्त करना और इसे आयताकार स्क्रीन क्षेत्र से तुलना करना पर्याप्त नहीं है।
एचडी

मैं @HD से सहमत हूं। इसके अलावा, यह तब समस्या पैदा करेगा जब तत्व बड़ा होगा border-radiusजैसा कि मैंने @ अजलर के उत्तर के ऊपर अपनी टिप्पणी में बताया है।
जय दादानिया

7

यहाँ 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');
   }
}

आशा है कि यह काम करता है, यहाँ एक पहेली है


3
यह मेरे लिए बॉक्स से बाहर काम नहीं किया। मुझे event.clientX, event.clientYइसके बजाय उपयोग करने की आवश्यकता है , क्योंकि वे व्यूपोर्ट के सापेक्ष हैं और पृष्ठ के नहीं। मुझे आशा है कि एक और खोई हुई आत्मा को वहां से बाहर निकालने में मदद मिलेगी।
जॉन अब्राम्स

7

एक सरल उपाय यह है pointer-events: noneकि ट्रिगर को रोकने के लिए चाइल्ड कंपोनेंट में css नियम जोड़ा जाए 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>


मुझे भी यही समस्या थी और आपका समाधान बहुत काम करता है। दूसरों के लिए टिप, यह मेरा मामला था: यदि आप जिस चाइल्ड एलिमेंट को ड्रैग ईवेंट को नजरअंदाज करने की कोशिश कर रहे हैं , वह उस एलिमेंट का क्लोन है, जिसे ड्रैग किया जा रहा है (विजुअल प्रिव्यू हासिल करने की कोशिश कर रहा है), आप क्लोन बनाते समय ड्रैगस्टार्ट के अंदर इसका इस्तेमाल कर सकते हैं :dragged = event.target;clone = dragged.cloneNode();clone.style.pointerEvents = 'none';
स्क्रैमौच

4

यकीन नहीं है कि अगर यह क्रॉस ब्राउज़र है, लेकिन मैंने क्रोम में परीक्षण किया और यह मेरी समस्या को हल करता है:

मैं पूरे पृष्ठ पर एक फ़ाइल को खींचना और छोड़ना चाहता हूं, लेकिन जब मैं बाल तत्व पर खींचता हूं तो मेरा ड्रैगवेलव निकाल दिया जाता है। मेरा फिक्स माउस के 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;
});

1
हैकी लेकिन चतुर। मुझे पसंद है। मेरे लिए काम किया।
कपकेककिड

1
ओह, मैं कैसे चाहता हूं कि इस उत्तर में अधिक वोट थे! धन्यवाद
किर्बी

4

मैंने इस सटीक मुद्दे को संभालने के लिए ड्रैगस्टर नाम की एक छोटी सी लाइब्रेरी लिखी है , हर जगह काम करता है सिवाय चुपचाप IE में कुछ भी करने के (जो DOM इवेंट कंस्ट्रक्टर्स का समर्थन नहीं करता है, लेकिन jQuery की कस्टम घटनाओं का उपयोग करके कुछ ऐसा ही लिखना बहुत आसान होगा)


बहुत उपयोगी (कम से कम मेरे लिए जहां मुझे केवल क्रोम की परवाह है)।
एम काट्ज

4

मैं एक ही मुद्दा रहा था और pk7s समाधान का उपयोग करने की कोशिश की। इसने काम किया लेकिन इसे बिना किसी अतिरिक्त डोम तत्वों के थोड़ा बेहतर किया जा सकता था।

मूल रूप से यह विचार समान है - ड्रापेबल क्षेत्र पर एक अतिरिक्त अवास्तविक ओवरले जोड़ें। केवल किसी अतिरिक्त डोम तत्वों के बिना ऐसा करने देता है। यहाँ हिस्सा है सीएसएस छद्म तत्व खेलने के लिए आते हैं।

जावास्क्रिप्ट

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

सीएसएस

यह नियम ड्रापेबल क्षेत्र के लिए पूरी तरह से कवर ओवरले बनाएगा।

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

यहाँ पूर्ण समाधान है: http://jsfiddle.net/F6GDq/8/

मुझे आशा है कि यह उसी समस्या के साथ किसी को भी मदद करता है।


1
कभी-कभी क्रोम पर काम नहीं करता है (ड्रैगलीव को ठीक से नहीं पकड़ता है)
टिमो हुओवेनन

4

बस जांचें कि क्या तत्व से अधिक खींचा गया बच्चा है, यदि यह है, तो अपनी 'ड्रैगओवर' शैली की कक्षा को न निकालें। बहुत सरल और मेरे लिए काम करता है:

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

मेरे लिए सबसे सरल समाधान की तरह दिखता है, और इसने मेरी समस्या को हल किया। धन्यवाद!
फ्रांसेस्को मार्केटी-स्टैसी

3

मैं उसी समस्या में फंस गया हूं और यहां मेरा समाधान है - जो मुझे लगता है कि बहुत आसान है, फिर ऊपर। मुझे यकीन नहीं है कि यह क्रॉसब्रोसर है (यहां तक ​​कि बबलिंग ऑर्डर पर निर्भर हो सकता है)

मैं सादगी के लिए 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)

और इसके बारे में है। :) यह काम करता है क्योंकि भले ही बच्चे पर onnter माता-पिता के आगे बढ़ने से पहले आग लगाता है, हम इसे आदेश को थोड़ा उलटने में देरी करते हैं, इसलिए क्लास को पहले हटा दिया जाता है और फिर एक मील के पत्थर के बाद फिर से लगाया जाता है।


केवल एक चीज जो यह स्निपेट करता है, वह 'होवरेड' वर्ग को अगले टिक चक्र ('ड्रैगलीव' घटना को बेकार बनाते हुए) को हटाकर रोका जा सकता है।
null

यह बेकार नहीं है। यदि आप माता-पिता को छोड़ देते हैं तो यह उम्मीद के मुताबिक काम करेगा। इस समाधान की शक्ति यह सादगी है, यह आदर्श या सबसे अच्छा नहीं है। बेहतर समाधान यह होगा कि हम एक बच्चे पर एक दर्ज करें, अगर हम सिर्फ बच्चे में प्रवेश करते हैं, और यदि ऐसा नहीं है तो छुट्टी की घटना को ट्रिगर करें। यह परीक्षण, अतिरिक्त गार्ड, पोते के लिए जयकार, आदि की आवश्यकता होगी
Marcin Raczkowski

3

मैंने ड्रिप-ड्रॉप नामक एक ड्रैग-एंड-ड्रॉप मॉड्यूल लिखा है जो इस अजीब व्यवहार को ठीक करता है, दूसरों के बीच। यदि आप एक अच्छे निम्न-स्तरीय ड्रैग-एंड-ड्रॉप मॉड्यूल की तलाश कर रहे हैं, तो आप किसी भी चीज़ के आधार के रूप में उपयोग कर सकते हैं (फ़ाइल अपलोड, इन-ऐप ड्रैग-एंड-ड्रॉप, ड्रैगिंग से या बाहरी स्रोतों तक), आपको इसकी जांच करनी चाहिए मॉड्यूल बाहर:

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

एक वैकल्पिक कार्य समाधान, थोड़ा सरल।

//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) {

यह Chrome में हमेशा काम करने के लिए प्रकट नहीं होता है। clientXजब अवसर माउस बॉक्स के बाहर होता है, तो मैं 0 से ऊपर प्राप्त करता हूं । दी, मेरे तत्व हैंposition:absolute
हेंगजी

क्या यह हर समय या कभी-कभी ही होता है? क्योंकि अगर माउस बहुत तेजी से आगे बढ़ रहा है (विंडो के बाहर), तो आपको गलत मान मिल सकते हैं।
प्रोफेट

यह 90% समय होता है। ऐसे दुर्लभ मामले हैं (10 में से 1 बार) जहां मैं इसे 0. तक पहुंचा सकता हूं। मैं फिर से माउस को धीमा करने की कोशिश करूंगा, लेकिन मैं यह नहीं कह सकता था कि मैं जल्दी से आगे बढ़ रहा था (शायद जिसे आप सामान्य गति कहेंगे)।
हेंजी

2

इतने घंटे बिताने के बाद मुझे वह सुझाव ठीक वैसा ही काम करने का मिला। मैं केवल एक क्यू प्रदान करना चाहता था जब फाइलें खींची जाती थीं, और दस्तावेज़ ड्रैगओवर, ड्रैगवेलवे क्रोम ब्राउज़र पर दर्दनाक फ़्लिकर पैदा कर रहा था।

यह मैंने इसे कैसे हल किया, यह भी उपयोगकर्ता के लिए उचित संकेतों में फेंक रहा है।

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

1

मुझे भी इसी तरह की समस्या थी - बॉडी के लिए ड्रैगवेल की घटना पर ड्रॉपज़ोन को छिपाने के लिए मेरा कोड आकस्मिक रूप से निकाल दिया गया था, जब Google क्रोम में ड्रॉपज़ोन झिलमिलाहट कर रहे बाल तत्वों को मँडरा रहा था।

मैं इसे तुरंत कॉल करने के बजाय ड्रॉपज़ोन को छिपाने के लिए फ़ंक्शन शेड्यूल करके इसे हल करने में सक्षम था। फिर, यदि कोई अन्य ड्रैगओवर या ड्रैगलीव निकाल दिया जाता है, तो निर्धारित फ़ंक्शन कॉल रद्द कर दिया जाता है।

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

" ड्रैगलीव " घटना को निकाल दिया जाता है जब माउस पॉइंटर टारगेट कंटेनर के ड्रैगिंग क्षेत्र से बाहर निकलता है।

कौन सा कई मामलों में केवल माता पिता हो सकता है के रूप में भावना का एक बहुत बनाता है droppable वंश और नहीं। मुझे लगता है कि event.stopPropogation () को इस मामले को संभालना चाहिए था, लेकिन लगता है कि यह चाल नहीं करता है।

ऊपर उल्लेख किया गया है कि कुछ समाधान अधिकांश मामलों के लिए काम करते हैं, लेकिन उन बच्चों के मामले में विफल रहता है जो ड्रैगेंटर / ड्रैगवेल की घटनाओं का समर्थन नहीं करते हैं, जैसे कि आइफ्रेम

1 वर्कअराउंड इवेंट check.relatedTarget को चेक करना है और सत्यापित करना है कि यह कंटेनर के अंदर रहता है तो ड्रैगवेल घटना को अनदेखा करें जैसा मैंने यहाँ किया है:

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

हल किया ..!

पूर्व के लिए किसी भी सरणी को घोषित करें:

targetCollection : any[] 

dragenter: function(e) {
    this.targetCollection.push(e.target); // For each dragEnter we are adding the target to targetCollection 
    $(this).addClass('red');
},

dragleave: function() {
    this.targetCollection.pop(); // For every dragLeave we will pop the previous target from targetCollection
    if(this.targetCollection.length == 0) // When the collection will get empty we will remove class red
    $(this).removeClass('red');
}

बाल तत्वों के बारे में चिंता करने की आवश्यकता नहीं है।


1

मैंने इन सभी उत्तरों के माध्यम से पढ़ने के बाद भी इसके साथ एक बहुत संघर्ष किया, और सोचा कि मैं आपके साथ अपना समाधान साझा कर सकता हूं, क्योंकि मुझे लगा कि यह सरल दृष्टिकोणों में से एक हो सकता है, हालांकि कुछ अलग। मेरा विचार बस dragleaveइवेंट श्रोता को पूरी तरह से छोड़ देना था , और ड्रैगवर्ल व्यवहार को प्रत्येक नए ड्रैगेंटर ईवेंट के साथ कोड करना निकाल दिया, जबकि यह सुनिश्चित करते हुए कि ड्रैगेंटर घटनाओं को अनावश्यक रूप से निकाल नहीं दिया जाएगा।

नीचे मेरे उदाहरण में, मेरे पास एक टेबल है, जहां मैं ड्रैग एंड ड्रॉप एपीआई के माध्यम से एक दूसरे के साथ तालिका पंक्ति सामग्री का आदान-प्रदान करने में सक्षम होना चाहता हूं। पर dragenter, सीएसएस वर्ग को पंक्ति तत्व में जोड़ा जाएगा जिसमें आप वर्तमान में अपने तत्व को खींच रहे हैं, इसे उजागर करने के लिए, और dragleaveइस वर्ग को हटा दिया जाएगा।

उदाहरण:

बहुत मूल HTML तालिका:

<table>
  <tr>
    <td draggable="true" class="table-cell">Hello</td>
  </tr>
  <tr>
    <td draggable="true" clas="table-cell">There</td>
  </tr>
</table>

और dragenter ईवेंट हैंडलर समारोह, हर तालिका सेल पर जोड़ा (एक तरफ dragstart, dragover, drop, और dragendसंचालकों, जो इस सवाल का विशिष्ट नहीं हैं, इसलिए यहां कॉपी नहीं):

/*##############################################################################
##                              Dragenter Handler                             ##
##############################################################################*/

// When dragging over the text node of a table cell (the text in a table cell),
// while previously being over the table cell element, the dragleave event gets
// fired, which stops the highlighting of the currently dragged cell. To avoid
// this problem and any coding around to fight it, everything has been
// programmed with the dragenter event handler only; no more dragleave needed

// For the dragenter event, e.target corresponds to the element into which the
// drag enters. This fact has been used to program the code as follows:

var previousRow = null;

function handleDragEnter(e) {
  // Assure that dragenter code is only executed when entering an element (and
  // for example not when entering a text node)
  if (e.target.nodeType === 1) {
    // Get the currently entered row
    let currentRow = this.closest('tr');
    // Check if the currently entered row is different from the row entered via
    // the last drag
    if (previousRow !== null) {
      if (currentRow !== previousRow) {
        // If so, remove the class responsible for highlighting it via CSS from
        // it
        previousRow.className = "";
      }
    }
    // Each time an HTML element is entered, add the class responsible for
    // highlighting it via CSS onto its containing row (or onto itself, if row)
    currentRow.className = "ready-for-drop";
    // To know which row has been the last one entered when this function will
    // be called again, assign the previousRow variable of the global scope onto
    // the currentRow from this function run
    previousRow = currentRow;
  }
}

कोड में बहुत बुनियादी टिप्पणियां शेष हैं, जैसे कि यह कोड शुरुआती लोगों के लिए भी उपयुक्त है। उम्मीद है इससे आपकी सहायता होगी! ध्यान दें कि आपको काम करने के लिए प्रत्येक टेबल सेल में उपरोक्त सभी घटना श्रोताओं को जोड़ने की आवश्यकता होगी।


0

यहां घटनाओं के समय के आधार पर एक और दृष्टिकोण है।

dragenterघटना चाइल्ड तत्व से रवाना पेरेंट तत्व द्वारा कब्जा कर लिया जा सकता है और यह हमेशा से पहले होता है dragleave। इन दो घटनाओं के बीच का समय वास्तव में कम है, किसी भी संभावित मानव माउस कार्रवाई से कम है। तो, यह विचार उस समय को याद करने के लिए dragenterहोता है जब एक घटना और फ़िल्टर dragleaveघटनाएं होती हैं जो "बहुत जल्दी नहीं" के बाद होती हैं ...

यह छोटा उदाहरण क्रोम और फ़ायरफ़ॉक्स पर काम करता है:

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

pimvdb ..

आप ड्रैगवेलवे के बजाय ड्रॉप का उपयोग करने का प्रयास क्यों नहीं करते हैं । इसने मेरे लिए काम किया। आशा है इससे तुम्हारी समस्या का समाधान हो गया होगा।

कृपया jsField: 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");
                 }
                });

2
यदि उपयोगकर्ता अपना मन बदल लेता है और फ़ाइल को ब्राउज़र से वापस बाहर निकालता है, तो यह लाल रहेगा।
ZachB

0

आप एक transitioningध्वज के साथ एक टाइमआउट का उपयोग कर सकते हैं और शीर्ष तत्व को सुन सकते हैं । dragenter/ dragleaveबच्चे की घटनाओं से कंटेनर तक बुलबुला जाएगा।

चूंकि कंटेनर के dragenterपहले बाल तत्व आग लगाता है dragleave, हम ध्वज शो को 1ms के लिए संक्रमण के रूप में सेट करेंगे ... dragleaveश्रोता ध्वज के लिए जाँच करेगा इससे पहले कि 1ms ऊपर है।

ध्वज केवल बाल तत्वों में परिवर्तन के दौरान सही होगा, और जब एक मूल तत्व (कंटेनर में) में संक्रमण होता है तो यह सच नहीं होगा

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

आपको ड्रैग टारगेट की सभी चाइल्ड ऑब्जेक्ट्स के लिए पॉइंटर घटनाओं को हटाने की आवश्यकता है।

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) {
                //
            }
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.