अभिभावक तत्व का 'ड्रैगलीव' बच्चों के तत्वों पर खींचते समय आग लगाता है


163

अवलोकन

मेरे पास निम्न HTML संरचना है और मैंने तत्वों को ईवेंट dragenterऔर dragleaveघटनाओं से जोड़ा है <div id="dropzone">

<div id="dropzone">
    <div id="dropzone-content">
        <div id="drag-n-drop">
            <div class="text">this is some text</div>
            <div class="text">this is a container with text and images</div>
        </div>
    </div>
</div>

संकट

जब मैं किसी फ़ाइल को खींचता हूं <div id="dropzone">, तो dragenterघटना अपेक्षित रूप से निकाल दी जाती है। हालाँकि, जब मैं अपने माउस को किसी चाइल्ड एलिमेंट पर ले जाता हूं, जैसे कि <div id="drag-n-drop">, dragenterईवेंट को <div id="drag-n-drop">एलीमेंट के लिए निकाल दिया जाता है और फिर dragleaveईवेंट को <div id="dropzone">एलीमेंट के लिए निकाल दिया जाता है।

यदि मैं <div id="dropzone">फिर से तत्व पर मंडराता हूं , तो dragenterघटना को फिर से निकाल दिया जाता है, जो शांत होता है, लेकिन फिर dragleaveघटना को बाल तत्व के लिए छोड़ दिया जाता है, इसलिए removeClassनिर्देश निष्पादित किया जाता है, जो शांत नहीं है।

यह व्यवहार 2 कारणों से समस्याग्रस्त है:

  1. मैं केवल संलग्न कर रहा हूँ dragenterऔर dragleaveकरने के लिए <div id="dropzone">तो मुझे समझ नहीं आता क्यों बच्चों तत्वों इन घटनाओं में अच्छी तरह से जुड़ा हुआ है।

  2. मैं अभी भी <div id="dropzone">अपने बच्चों पर मंडराते हुए तत्व को खींच रहा हूं इसलिए मैं dragleaveआग नहीं लगाना चाहता !

jsFiddle

यहाँ एक jsFiddle के साथ टिंकर करने के लिए है: http://jsfiddle.net/yYF3S/2/

सवाल

तो ... मैं इसे कैसे बना सकता हूं जब मैं किसी <div id="dropzone">तत्व पर फ़ाइल खींच रहा हूं , dragleaveतब भी आग नहीं लगती है जब मैं किसी भी बच्चे के तत्वों पर खींच रहा हूं ... यह केवल आग होनी चाहिए जब मैं <div id="dropzone">तत्व को छोड़ देता हूं .. । तत्व की सीमाओं के भीतर कहीं भी घूमना / घसीटना घटना को ट्रिगर नहीं करना चाहिएdragleave

मुझे यह क्रॉस-ब्राउज़र संगत होना चाहिए, कम से कम उन ब्राउज़रों में जो HTML5 ड्रैग-एन-ड्रॉप का समर्थन करते हैं, इसलिए यह उत्तर पर्याप्त नहीं है।

ऐसा लगता है कि Google और ड्रॉपबॉक्स ने इसका पता लगा लिया है, लेकिन उनका स्रोत कोड छोटा / जटिल है इसलिए मैं उनके कार्यान्वयन से यह पता लगाने में सक्षम नहीं हूं।


घटना के प्रसार को रोकेंe.stopPropagation();
ब्लेंडर

मुझे लगता है कि मैं पहले से ही हूं ... अपडेट को देखें
Hristo

क्या आप कहीं jsfiddle.net पर एक डेमो पोस्ट कर सकते हैं। लोग इसके साथ छेड़छाड़ कर सकते हैं?
ब्लेंडर

@ ब्लेंडर ... ज़रूर बात, मुझे एक दो मिनट दे दो!
हिस्टो

@Blender ... मैं मेरे सवाल का एक बेला के साथ अद्यतन
ह्रिस्टो

जवाबों:


171

यदि आपको घटनाओं को बाल तत्वों से बांधने की आवश्यकता नहीं है, तो आप हमेशा पॉइंटर-ईवेंट संपत्ति का उपयोग कर सकते हैं।

.child-elements {
  pointer-events: none;
}

4
सबसे अच्छा उपाय! मैंने यह भी नहीं सोचा था कि मैं इतने सुरुचिपूर्ण तरीके से सीएसएस का उपयोग करके समस्या को हल कर सकता हूं। आपका बहुत बहुत धन्यवाद!
सर्ग ६६

1
अरे हां। यह बात है!
mcmlxxxiii

23
इस दृष्टिकोण के लिए केवल नकारात्मक यह है कि यह बाल तत्वों पर सभी सूचक घटनाओं को nukes करता है (उदाहरण के लिए वे अब अलग :hoverशैली नहीं रख सकते हैं या इवेंट हैंडलर पर क्लिक कर सकते हैं)। यदि आप उन घटनाओं को संरक्षित करना चाहते हैं, तो यहां एक और समाधान मैं उपयोग कर रहा हूं: bensmithett.github.io/dragster
बेन

2
अपने ड्रॉपज़ोन के सभी बच्चों तक पहुंचने के लिए सीएसएस चाइल्ड सिलेक्टर के साथ मिलाएं: .dropzone * {pointer-events: none;}
फिलिप एफ

7
आप पहले से ही jQuery का उपयोग कर रहे हैं, इसलिए केवल $('.element').addClass('dragging-over')उस तत्व पर जिसे आप खींच रहे हैं, और $('.element').removeClass('dragging-over')जब आप बाहर निकालते हैं। तब आपके CSS में आप हो सकते हैं .element.dragging-over * { pointer-events: none; }। जब आप ओवर ड्रैग कर रहे हों, तो सभी बाल तत्वों से सूचक घटनाओं को हटा देता है।
गैविन

56

मुझे आखिरकार एक समाधान मिला जिससे मैं खुश हूं। मुझे वास्तव में ऐसा करने के कई तरीके मिले जो मैं चाहता हूं, लेकिन वर्तमान समाधान के रूप में कोई भी सफल नहीं था ... एक समाधान में, #dropzoneतत्व में एक सीमा को जोड़ने / हटाने के परिणामस्वरूप मुझे लगातार चंचल अनुभव हुआ ... दूसरे में, सीमा यदि आप ब्राउज़र से दूर मँडराते हैं तो कभी नहीं हटाया गया था।

वैसे भी, मेरा सबसे अच्छा hacky समाधान यह है:

var dragging = 0;

attachEvent(window, 'dragenter', function(event) {

    dragging++;
    $(dropzone).addClass('drag-n-drop-hover');

    event.stopPropagation();
    event.preventDefault();
    return false;
});

attachEvent(window, 'dragover', function(event) {

    $(dropzone).addClass('drag-n-drop-hover');

    event.stopPropagation();
    event.preventDefault();
    return false;
});

attachEvent(window, 'dragleave', function(event) {

    dragging--;
    if (dragging === 0) {
        $(dropzone).removeClass('drag-n-drop-hover');
    }

    event.stopPropagation();
    event.preventDefault();
    return false;
});

यह बहुत अच्छा काम करता है, लेकिन फ़ायरफ़ॉक्स में मुद्दे सामने आए क्योंकि फ़ायरफ़ॉक्स डबल-इनवॉइसिंग था dragenterइसलिए मेरा काउंटर बंद था। लेकिन फिर भी, यह एक बहुत ही सुंदर समाधान नहीं है।

फिर मैं इस सवाल पर अड़ गया कि खिड़की से बाहर खींचते समय फ़ायरफ़ॉक्स में ड्रैगवेल घटना का पता कैसे लगाया जाए

इसलिए मैंने उत्तर लिया और इसे अपनी स्थिति पर लागू किया:

$.fn.dndhover = function(options) {

    return this.each(function() {

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

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

        self.on('dragleave', function(event) {
            /*
             * Firefox 3.6 fires the dragleave event on the previous element
             * before firing dragenter on the next one so we introduce a delay
             */
            setTimeout(function() {
                collection = collection.not(event.target);
                if (collection.size() === 0) {
                    self.trigger('dndHoverEnd');
                }
            }, 1);
        });
    });
};

$('#dropzone').dndhover().on({
    'dndHoverStart': function(event) {

        $('#dropzone').addClass('drag-n-drop-hover');

        event.stopPropagation();
        event.preventDefault();
        return false;
    },
    'dndHoverEnd': function(event) {

        $('#dropzone').removeClass('drag-n-drop-hover');

        event.stopPropagation();
        event.preventDefault();
        return false;
    }
});

यह साफ और सुरुचिपूर्ण है और लगता है कि मैंने अब तक परीक्षण किए गए प्रत्येक ब्राउज़र में काम किया है (अभी तक IE का परीक्षण नहीं किया है)।


यह अब तक का सबसे अच्छा समाधान है। केवल एक समस्या यह है कि जब आप कोई फ़ाइल जोड़ते हैं तो यह कोड काम नहीं करता है, इसे हटा दें और दूसरी फ़ाइल को इसके ऊपर खींचें। होवरईंड को बढ़ाने और होवरस्टार्ट को फिर से बढ़ाने के बाद ही यह कोड फिर से काम करता है।
मिस्टिकइर्थ

जब यह काम नहीं करता है तो @MysticEarth आप एक jsFiddle को एक साथ रख सकते हैं?
ह्रिस्टो

1
आपके उत्तर के लिए धन्यवाद। यह वास्तव में मददगार था, क्योंकि HTML5 ड्रैग एंड ड्रॉप इंटरफेस और इवेंट श्रोताओं को वास्तव में दर्दनाक हो सकता है। यह पागल घटनाओं को संभालने का सबसे अच्छा तरीका है, खासकर जब आप ड्रॉप ज़ोन तत्वों के कई उदाहरणों को संभालना चाहते हैं।
निको ओ

हमें stopPropagation () preventDefault () को कॉल करने और झूठे वापस करने की आवश्यकता क्यों है। झूठ झूठ पर्याप्त होना चाहिए। इसे होना चाहिए ?
देजो

यह बेमानी है, लेकिन कॉलिंग stopPropagation()और preventDefault()पसंद की जाती है। मैं छोड़ दूँगा return false
16

38

यह थोड़ा बदसूरत है लेकिन यह काम करता है!

अपने 'ड्रैगेंटर' हैंडलर में event.target (आपके क्लोजर के अंदर एक वैरिएबल, या जो भी हो) स्टोर करें, फिर अपने 'ड्रैगवेलवे' हैंडलर में केवल तभी अपना कोड फायर करें, अगर EventTarget === आपके द्वारा स्टोर किया गया हो।

यदि आपका 'ड्रैगेंटर' तब फायरिंग कर रहा है जब आप इसे नहीं चाहते हैं (यानी जब बच्चे तत्वों को छोड़ने के बाद प्रवेश कर रहे हैं), तो आखिरी बार जब यह माता-पिता को छोड़ता है, तो यह माता-पिता पर छोड़ देता है, इसलिए माता-पिता हमेशा रहेंगे अंतिम 'ड्रैगेंटर' का इरादा 'ड्रैगलीव' से पहले था।

(function () {

    var droppable = $('#droppable'),
        lastenter;

    droppable.on("dragenter", function (event) {
        lastenter = event.target;
        droppable.addClass("drag-over");            
    });

    droppable.on("dragleave", function (event) {
        if (lastenter === event.target) {
            droppable.removeClass("drag-over");
        }
    });

}());

मैं बाद में यह कोशिश करूँगा। अगर कुछ भी है, तो यह मेरे समाधान से साफ दिखता है, लेकिन मुझे यकीन नहीं हो सकता है कि क्रॉस-ब्राउज़र कैसे संगत है, बस इसे देखकर। आपने यह कहां परीक्षण किया है?
हिस्टो

1
केवल क्रोम, और केवल इस धारणा पर काम कर सकते हैं कि बाल तत्वों और कंटेनर के बीच एक भौतिक अंतर है।
हैकलीक्रेक

5
मेरा पसंदीदा जवाब यहाँ पर। बदसूरत महसूस नहीं करता है :)
मैट वे

1
IE में मेरे लिए काम करता है, क्रोम, एफएफ
विसेन्टियू Bacioiu

1
बच्चों पर ड्रैग शुरू होने पर यह काम नहीं करता है। उदाहरण के लिए, किसी चीज को दूसरी खिड़की से इस तरह से खींचना कि बच्चे के अंदर ड्रैग शुरू हो जाए।
FINDarkside

29

सबसे पहले, मैं इस pointer-events: noneदृष्टिकोण को छोड़ने वाले लोगों से सहमत था । लेकिन फिर मैंने खुद से पूछा:

क्या आपको वास्तव में बच्चे को काम करने के लिए पॉइंटर-ईवेंट की आवश्यकता है जबकि ड्रैगिंग प्रगति पर है ?

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

मेरे मामले में, मैं कुछ इस तरह का उपयोग करता हूं कि पेरेंट कंटेनर के सभी बच्चे नोड्स के लिए पॉइंटर घटनाओं को चुनिंदा रूप से बंद करें:

  div.drag-target-parent-container.dragging-in-progress * {
    pointer-events: none;
  }

/ ईवेंट हैंडलर्स dragging-in-progressमें कक्षा को जोड़ने / हटाने के लिए अपने पसंदीदा दृष्टिकोण का उपयोग करें , जैसा कि मैंने किया था , एट या उसी में किया था । अल।dragEnterdragLeavedragStart


1
यह समाधान दोनों सबसे सरल है और (जहाँ तक मैं बता सकता हूँ) फुल-प्रूफ है। बस dragstartघटना में वर्ग जोड़ें और इसे अंदर निकालें dragend
cmann

यह बहुत अच्छा समाधान है, लेकिन सही नहीं है। यदि ड्रैग चाइल्ड एलिमेंट (दूसरी विंडो से ड्रैग करना) पर शुरू होता है, तो ड्रैगनेटर कभी भी फेयर नहीं होता है। संभवत: माउस को तेजी से स्थानांतरित करना संभव है, जब आप बच्चे को ले जाते हैं, तो ड्रैगनेटर को निकाल नहीं दिया जाता है, लेकिन इसके बाद 100% सुनिश्चित नहीं होता है।
FINDarkside

12

यह Chrome बग प्रतीत होता है।

केवल एक ही उपाय जो मैं सोच सकता था, वह था अपनी घटनाओं को पकड़ने के लिए एक पारदर्शी ओवरले तत्व बनाना: http://jsfiddle.net/yYF3S/10/

जेएस :

$(document).ready(function() {
    var dropzone = $('#overlay');

    dropzone.on('dragenter', function(event) {
        $('#dropzone-highlight').addClass('dnd-hover');
    });

    dropzone.on('dragleave', function(event) {
        $('#dropzone-highlight').removeClass('dnd-hover');
    });

});​

HTML :

<div id="dropzone-highlight">
    <div id="overlay"></div>

    <div id="dropzone" class="zone">
        <div id="drag-n-drop">
            <div class="text1">this is some text</div>
            <div class="text2">this is a container with text and images</div>
        </div>
    </div>
</div>

<h2 draggable="true">Drag me</h2>

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

यहाँ एक उदाहरण है फिडल कि आपका समाधान संतुष्ट नहीं करता है ... jsfiddle.net/UnsungHero97/yYF3S/11
Hristo

मैं उलझन में हूं। आपको बाल तत्वों के साथ बातचीत करने की आवश्यकता क्यों है?
ब्लेंडर

मेरे विशेष मामले में, "ड्रॉपज़ोन" का एक बच्चा तत्व एक फ़ाइल चयन बटन है ... इसलिए यदि मैं फ़ाइलों को खींचना और छोड़ना नहीं चाहता, तो मैं इनपुट तत्व का उपयोग करके उनका चयन कर सकता हूं। लेकिन ओवरले के साथ ... मैं इनपुट तत्व पर क्लिक नहीं कर सकता। सही बात?
हिस्टो

@ ब्लेंडर अधिकांश मामलों में हमें डेस्कटॉप से ​​एक फ़ाइल को खींचने की आवश्यकता होती है, पृष्ठ से एक तत्व नहीं, इसलिए यह थोड़े काम नहीं करता है।
मालती ब्रीडिस

5

समस्या यह है, कि ड्रॉपज़ोन के अंदर आपके तत्व निश्चित रूप से ड्रॉपज़ोन का हिस्सा हैं और जब आप बच्चों में प्रवेश करते हैं, तो आप माता-पिता को छोड़ देते हैं। इसे हल करना आसान नहीं है। आप बच्चों के साथ घटनाओं को जोड़ने की कोशिश कर सकते हैं और अपनी कक्षा को फिर से जनक से जोड़ सकते हैं।

$("#dropzone,#dropzone *").on('dragenter', function(event) {

    // add a class to #dropzone

    event.stopPropagation(); // might not be necessary
    event.preventDefault();
    return false;
});

आपकी घटनाएं अभी भी कई बार आग लगायेंगी, लेकिन कोई नहीं देखेगा।

// संपादित करें: ड्रैगवेल घटना को स्थायी रूप से अधिलेखित करने के लिए ड्रैगोव घटना का उपयोग करें:

$("#dropzone,#dropzone *").on('dragenter dragover', function(event) {

    // add a class to #dropzone

    event.stopPropagation(); // might not be necessary
    event.preventDefault();
    return false;
});

ड्रैगवेल की घटना को केवल ड्रॉपज़ोन के लिए परिभाषित करें।


2
हालांकि यह समस्या हल नहीं होगी। असली मुद्दा यह है dragleave... जब मैं एक बच्चे को छोड़ता हूं, तो मैं अभी भी माता-पिता के भीतर रह सकता हूं, #dropzoneलेकिन वह dragenterफिर से इस घटना को आग नहीं देगा :(
हिस्टो

क्या आप सुनिश्चित हैं, कि ड्रैगेंटर को फिर से नहीं निकाला गया है?
ओलिवर

आह ठीक है ... इसे फिर से निकाल दिया जाता है, हालांकि, इसे निकाल दिए जाने के बाद, dragleaveघटना को बाल तत्व के लिए छोड़ दिया जाता है, इसलिए फिर से removeClassनिर्देश निष्पादित किया जाता है
हिस्टो

मैं dragleaveकेवल के लिए परिभाषित नहीं कर सकता #dropzone... अगर मैं कर सकता था, तो मुझे यह समस्या नहीं होगी।
हिस्टो

नहीं, मेरा मतलब है कि बच्चों के लिए ड्रैगव्लव के लिए घटनाओं को न जोड़ें।
ओलिवर

4

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

#dropzone.dragover *{
   pointer-events: none;
}

और इसे अपने JS कोड में जोड़ें:

$("#dropzone").on("dragover", function (event) {
   $("#dropzone").addClass("dragover");
});

$("#dropzone").on("dragleave", function (event) {
   $("#dropzone").removeClass("dragover");
});

2
मेरे लिए यह परिणाम ओवरले में लगातार चमकता है।
एंड्री मिखायलोव - lolmaus

3

यदि आप jQuery का उपयोग कर रहे हैं, तो इसे देखें: देखें https://github.com/dancork/jquery.event.dragout

यह वास्तव में बहुत बढ़िया है।

सच्ची ड्रैगवेल की कार्यक्षमता को संभालने के लिए बनाई गई विशेष घटना।

HTML5 ड्रैगवेलव इवेंट माउसआउट की तरह काम करता है। इस प्लगइन को ड्रैग करते हुए मूसलीव स्टाइल की कार्यक्षमता को दोहराने के लिए बनाया गया था।

उपयोग उदाहरण:

$ ('# myelement')। ('ड्रैगआउट', फंक्शन (इवेंट) {// Your CODE}) पर;

संपादित करें: वास्तव में, मुझे नहीं लगता कि यह jQuery पर निर्भर है, आप शायद इसके बिना भी कोड का उपयोग कर सकते हैं।


वाह! ड्रैगआउट एक ऐसी चीज है, जो मेरे लेआउट के लिए काम करती है, जिसमें बहुत सारे बच्चों के तत्व फायरिंग करते हैं dragleave, जबकि मैंने माता-पिता के ड्रॉपजोन को नहीं छोड़ा है।
मार्क केसन

अंतिम घंटे के लिए इस मुद्दे से लड़ने के बाद, dragoutएकमात्र समाधान था जिसने मेरे लिए काम किया।
जेसन हेज़ल

2

@ श्रीमान मेरे पास एक और अधिक सुंदर समाधान है। जांचें कि यदि वह ऐसी चीज है जिसका आप उपयोग कर सकते हैं।

आपका प्रयास बिल्कुल भी व्यर्थ नहीं गया। मैं पहली बार में आपका उपयोग करने में कामयाब रहा, लेकिन FF, Chrome में अलग-अलग समस्याएं थीं। इतने घंटे बिताने के बाद मुझे वह सुझाव ठीक वैसा ही काम करने का मिला।

यहां बताया गया है कि कार्यान्वयन कैसे होता है। मैंने ड्रॉप ज़ोन के बारे में उपयोगकर्ताओं को सही ढंग से मार्गदर्शन करने के लिए दृश्य संकेतों का लाभ उठाया।

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

आपको लगता है कि कुछ var dropZoneHideDelay=70, dropZoneVisible=true;
दायरों में से

@TimoHuovinen हाँ, सही है। दोनों dropZoneHideDelay, dropZoneVisibleदो भर की जरूरत है 'on'मेरी कार्यान्वयन में दस्तावेज़ की घटनाओं।
मुलाकात

2

मेरे दो सेंट: अपने ड्रॉपज़ोन पर एक परत छिपाएं, फिर जब आप ड्रैगेंटर को दिखाते हैं, और उस पर ड्रैगवेलव को लक्षित करें।

डेमो: https://jsfiddle.net/t6q4shat/

एचटीएमएल

<div class="drop-zone">
  <h2 class="drop-here">Drop here</h2>
  <h2 class="drop-now">Drop now!</h2>
  <p>Or <a href="#">browse a file</a></p>
  <div class="drop-layer"></div>
</div>

सीएसएस

.drop-zone{
  padding:50px;
  border:2px dashed #999;
  text-align:center;
  position:relative;
}
.drop-layer{
  display:none;
  position:absolute;
  top:0;
  left:0;
  bottom:0;
  right:0;
  z-index:5;
}
.drop-now{
  display:none;
}

जे एस

$('.drop-zone').on('dragenter', function(e){
    $('.drop-here').css('display','none');
    $('.drop-now').css('display','block');
    $(this).find('.drop-layer').css('display','block');
    return false;
});

$('.drop-layer').on('dragleave', function(e){
    $('.drop-here').css('display','block');
    $('.drop-now').css('display','none');
    $(this).css('display','none');
    return false;
});

सरल और प्रभावी! मैं स्टॉपप्रॉपैगेशन () मार्ग से नीचे जा रहा था और मुझे सभी बच्चों को इवेंट हैंडलर लगाना पसंद नहीं था। यह गड़बड़ लग रहा था लेकिन यह अच्छी तरह से काम करता है और लागू करने के लिए सरल है। अच्छा विचार।
जॉन कैटमूल

1

तो मेरे लिए दृष्टिकोण pointer-events: none;बहुत अच्छी तरह से काम नहीं किया ... तो यहाँ मेरा वैकल्पिक समाधान है:

    #dropzone {
        position: relative;
    }

    #dropzone(.active)::after {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        content: '';
    }

इस तरह यह dragleaveमाता-पिता (एक बच्चे पर) या dragoverएक बाल तत्व के लिए संभव नहीं है । उम्मीद है की यह मदद करेगा :)

* 'सक्रिय' वर्ग मैं dragenterया जब मैं जोड़ता हूं dragleave। लेकिन अगर आप इसके बिना काम कर रहे हैं तो सिर्फ क्लास छोड़ दें।


1
मैंने एक एम्बरजेएस डी एंड डी घटक में यह कोशिश की और 'सक्रिय' वर्ग को जोड़ने से प्रोग्रामेटिकली 40% धीमी गति से होता है जब माउस पैरेंट डिव (अंगारे-दृश्य) में प्रवेश करता है। यकीन नहीं है कि क्यों। लेकिन उस बंद को छोड़ना और यह बहुत अच्छा काम करता है, इसलिए इस सरल समाधान के लिए धन्यवाद। सफारी, क्रोम, फ़ायरफ़ॉक्स के नवीनतम संस्करणों (आज के अनुसार) पर एक मैक पर परीक्षण किया गया।
rmcsharry

1

इसके लिए सुपर सरल त्वरित सुधार, बड़े पैमाने पर परीक्षण नहीं किया गया है लेकिन अभी क्रोम में काम करता है।

कॉफ़िशस्क्रिप्ट का उपयोग करें।

  dragEndTimer = no

  document.addEventListener 'dragover', (event) ->
    clearTimeout dragEndTimer
    $('body').addClass 'dragging'
    event.preventDefault()
    return no

  document.addEventListener 'dragenter', (event) ->
    $('section').scrollTop(0)
    clearTimeout dragEndTimer
    $('body').addClass 'dragging'

  document.addEventListener 'dragleave', (event) ->
    dragEndTimer = setTimeout ->
      $('body').removeClass 'dragging'
    , 50

यह क्रोम झिलमिलाहट बग को ठीक करता है, या कम से कम इसकी अनुमति देता है जो मुझे परेशान कर रहा था।


1

यह उत्तर यहां पाया जा सकता है:

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

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

1

मेरा संस्करण:

$(".dropzone").bind("dragover", function(e){
    console.log('dragover');
});

$(".dropzone").bind("dragleave", function(e) {
  var stopDrag = false;
  if (!e.relatedTarget) stopDrag = true;
  else {
    var parentDrop = $(e.relatedTarget).parents('.dropzone');
    if (e.relatedTarget != this && !parentDrop.length) stopDrag = true;
  }

  if (stopDrag) {
    console.log('dragleave');
  }
});

इस लेआउट के साथ:

<div class="dropzone">
  <div class="inner-zone">Inner-zone</div>
</div>

मैं के लिए एलीमेंट क्लास की एक डंप कर दिया है e.target, e.currentTarget, e.relatedTargetदोनों के लिए dragoverऔर dragleaveघटनाओं।

इसने मुझे दिखाया कि मूल ब्लॉक छोड़ने पर ( .dropzone) e.relatedTargetइस ब्लॉक का बच्चा नहीं है, इसलिए मुझे पता है कि मैं ड्रॉपज़ोन से बाहर हूँ।


0

यहाँ, सबसे सरल समाधान में से एक ● one ●

इस फिडेल पर एक नज़र डालें - बॉक्स के अंदर कुछ फ़ाइल खींचने की कोशिश करें

आप ऐसा कुछ कर सकते हैं:

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

उसके द्वारा आपको पहले से ही पता होना चाहिए कि यहाँ क्या हो रहा है।
बस बेला पर एक नज़र रखना, तुम्हें पता है।


0

मुझे एक समान समस्या हुई है और मैंने इसे इस तरह से तय किया है:

समस्या: फ़ंक्शन ड्रॉप (ईवी) तब निकाल दिया जाता है जब उपयोगकर्ता "ड्रॉप ज़ोन" (उल तत्व) में एक तत्व को छोड़ देता है, लेकिन, दुर्भाग्यवश, यह भी कि जब तत्व अपने बच्चों में से एक (ली तत्व) में गिरा दिया जाता है।

जोड़:

function drop(ev) { 
ev.preventDefault(); 
data=ev.dataTransfer.getData('Text'); 
if(ev.target=="[object HTMLLIElement]")  
{ev.target.parentNode.appendChild(document.getElementById(data));}
else{ev.target.appendChild(document.getElementById(data));} 
} 

0

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

मुझे एक समाधान मिला जो जावास्क्रिप्ट और सीएसएस का एक अच्छा मिश्रण है। मान लें कि आपके पास divआईडी के साथ एक ड्रॉप करने योग्य ज़ोन है #drop। इसे अपनी जावास्क्रिप्ट में जोड़ें:

$('#drop').on('dragenter', function() {
    $(this).addClass('dragover');
    $(this).children().addClass('inactive');
});

$('#drop').on('dragleave', function() {
    $(this).removeClass('dragover');
    $(this).children().removeClass('inactive');
});

फिर, इसे अपने सीएसएस में जोड़ें, सभी बच्चों को निष्क्रिय करने के लिए कक्षा करेंगे .inactive:

#drop *.inactive {
    pointer-events: none;
}

इस प्रकार, जब तक उपयोगकर्ता बॉक्स पर तत्व को खींच रहा है, तब तक बच्चे तत्व निष्क्रिय रहेंगे।


0

यहां प्रस्तुत किए गए किसी भी वर्कआर्ड से मैं संतुष्ट महसूस नहीं कर रहा था, क्योंकि मैं बच्चों के तत्वों पर नियंत्रण नहीं खोना चाहता।

इसलिए मैंने एक अलग तर्क दृष्टिकोण का उपयोग किया है, इसे jQuery प्लगइन में अनुवाद करके jquery-draghandler कहा जाता है । यह उच्च प्रदर्शन की गारंटी देते हुए DOM को पूरी तरह से हेरफेर नहीं करता है। इसका उपयोग सरल है:

$(document).ready(function() {

    $(selector).draghandler({
        onDragEnter: function() {
            // $(this).doSomething();
        },
        onDragLeave: function() {
            // $(this).doSomethingElse();
        }
    });

});

यह किसी भी डोम कार्यक्षमता से समझौता किए बिना समस्या के साथ दोषपूर्ण व्यवहार करता है।

डाउनलोड करें, विवरण और इसकी गिट रिपॉजिटरी पर स्पष्टीकरण ।


मुझे आपके प्लगइन में ड्रैग एंटर इवेंट कैसे मिलेगा?
वुडी

मैंने वास्तव में आपके निर्देश का परीक्षण नहीं किया है, लेकिन मुझे लगता है कि यह काम नहीं करता है यदि मूल तत्व (ए) वास्तव में उस तत्व को घेरता नहीं है जिसे मैं (बी) जांचना चाहता हूं। उदाहरण के लिए, यदि बी के निचले किनारे और ए के निचले किनारे के बीच कोई पैडिंग नहीं है, तो ड्रैगेंटर को तत्व ए, दाएं के लिए कभी भी निकाल नहीं दिया जाएगा?
मार्सेलज

@marcelj एलिमेंट स्वयं ही बॉडी डॉक्यूमेंट हो सकता है, इसलिए आपको न्यूनतम पैडिंग के साथ वास्तव में एक आस-पास के तत्व (शरीर काम नहीं करता है) की आवश्यकता नहीं है। इस दृष्टिकोण के साथ मुझे जो सीमा मिली है, वह यह है कि यदि आप frames के साथ काम करते हैं और आपका तत्व इसकी सीमा पर है। उस स्थिति में, मैं इस दृष्टिकोण का सुझाव नहीं देता।
लुका फ़ागियोली

0

मैं वास्तव में पसंद कर रहा हूं जो मैं देख रहा हूं https://github.com/lolmaus/jquery.dragbetter/लेकिन एक संभावित विकल्प साझा करना चाहता था। मेरी सामान्य रणनीति यह थी कि जब इसे या किसी बच्चे को (बुदबुदाहट के माध्यम से) ड्रैगेंटरिंग किया जाता है, तो ड्रॉपज़ोन की पृष्ठभूमि की शैली को लागू करना चाहिए। तब मैं स्टाइल को हटा देता हूं जब ड्रॉप ज़ोन को खींचता हूं। आइडिया जब किसी बच्चे के पास जाता था, भले ही मैं उसे छोड़ने के दौरान ड्रॉपजोन से स्टाइल हटाता हूं (ड्रैगवेलव फायर करता है), मैं बस किसी भी बच्चे को ड्रैगेंटर करने पर पैरेंट ड्रॉपजोन के लिए स्टाइल को फिर से लागू करूंगा। समस्या यह है कि ड्रॉपज़ोन से ड्रॉपज़ोन के बच्चे के पास जाने पर, ड्रैगेंटर को ड्रैगवेलव से पहले बच्चे पर निकाल दिया जाता है, इसलिए मेरी शैलियों को क्रम से लागू किया गया। मेरे लिए समाधान एक टाइमर का उपयोग करने के लिए संदेश कतार में ड्रैगेंटर घटना को वापस करने के लिए मजबूर करने के लिए था, जिससे मुझे ड्रैगवेल के बाद इसे संसाधित करने की अनुमति मिली। मैंने टाइमर कॉलबैक पर ईवेंट को एक्सेस करने के लिए एक क्लोजर का उपयोग किया।

$('.dropzone').on('dragenter', function(event) {
  (function (event) {
    setTimeout(function () {
      $(event.target).closest('.dropzone').addClass('highlight');
    }, 0);
  }) (event.originalEvent); 
});

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


0

मैं खुद इसे लागू करने की कोशिश कर रहा था, और मुझे याक्वेरी या कोई भी प्लगइन नहीं चाहिए था।

मैं फ़ाइल अपलोड को संभालना चाहता था, मेरे लिए सबसे अच्छा समझा जाने वाला तरीका:

फ़ाइलें संरचना:

--- (अपलोड {अपलोड निर्देशिका)

--- -js/slyupload.js {जावास्क्रिप्ट फ़ाइल।}

--- सूचकांक। एफपी

--- अपलोड

--- style.css {थोड़ी स्टाइलिंग ..}

HTML कोड:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>my Dzone Upload...</title>
<link rel="stylesheet" href="styles.css" />
</head>

<body>
    <div id="uploads"></div>        
    <div class="dropzone" id="dropzone">Drop files here to upload</div>     
    <script type="text/javascript" src="js/slyupload.js"></script>      
</body>
</html>

फिर यह संलग्न जावास्क्रिप्ट फ़ाइल :: 'js / slyupload.js' है

<!-- begin snippet:  -->

<!-- language: lang-js -->

    // JavaScript Document

    //ondragover, ondragleave...


    (function(){        

        var dropzone = document.getElementById('dropzone');
        var intv;

        function displayUploads(data){
            //console.log(data, data.length);
            var uploads = document.getElementById('uploads'),anchor,x;

            for(x=0; x < data.length; x++){

                //alert(data[x].file);
                anchor = document.createElement('a');
                anchor.href = data[x].file;
                anchor.innerText = data[x].name;

                uploads.appendChild(anchor);
            }               
        }

        function upload(files){
            //console.log(files);
            var formData = new FormData(), 
                xhr      = new XMLHttpRequest(),    //for ajax calls...
                x;                                  //for the loop..

                for(x=0;x<files.length; x++){
                    formData.append('file[]', files[x]);

                    /*//do this for every file...
                    xhr = new XMLHttpRequest();

                    //open... and send individually..
                    xhr.open('post', 'upload.php');
                    xhr.send(formData);*/
                }

                xhr.onload = function(){
                    var data = JSON.parse(this.responseText);   //whatever comes from our php..
                    //console.log(data);
                    displayUploads(data);

                    //clear the interval when upload completes... 
                    clearInterval(intv);
                }                   

                xhr.onerror = function(){
                    console.log(xhr.status);
                }

                //use this to send all together.. and disable the xhr sending above...

                //open... and send individually..
                intv = setInterval(updateProgress, 50);
                xhr.open('post', 'upload.php');
                xhr.send(formData);

                //update progress... 
                 /* */                   
        }

        function updateProgress(){
            console.log('hello');
         }          

        dropzone.ondrop = function(e){
            e.preventDefault(); //prevent the default behaviour.. of displaying images when dropped...
            this.className = 'dropzone';
            //we can now call the uploading... 
            upload(e.dataTransfer.files); //the event has a data transfer object...
        }

        dropzone.ondragover = function(){
            //console.log('hello');
            this.className = 'dropzone dragover';
            return false;
        }

        dropzone.ondragleave = function(){
            this.className = 'dropzone';
            return false;
        }           
    }(window));

सीएसएस:

body{
	font-family:Arial, Helvetica, sans-serif; 
	font-size:12px;
}

.dropzone{
	width:300px; 
	height:300px;
	border:2px dashed #ccc;
	color:#ccc;
	line-height:300px;
	text-align:center;
}

.dropzone.dragover{
	border-color:#000;
	color:#000;
}


0

क्षमा करें, यह जावास्क्रिप्ट नहीं है, लेकिन मेरे लिए यह हल करने का सबसे तार्किक तरीका है। ब्राउज़र को ड्रॉपप्लव (पिछले तत्व का) को ड्रॉपरेंट (नए तत्व के) से पहले कॉल करना चाहिए, क्योंकि फॉर्स्ट चीज़ को लीक करने से पहले कुछ और दर्ज नहीं किया जा सकता है, मुझे समझ नहीं आता कि उन्होंने ऐसा क्यों किया! इसलिए आपको बस देरी करने की ज़रूरत है इस तरह से:

function mydropleave(e)
{
    e.preventDefault();
    e.stopPropagation();

    setTimeout(function(e){ //the things you want to do },1);
}

और गिराने वाला तो बूंद के बाद होगा, बस!


-1

के greedy : trueएक समारोह के रूप में बच्चे के लिए उपयोग करें droppable। फिर पहली परत पर क्लिक की गई केवल घटना शुरू करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.