javascript - एक बच्चे तत्व को घुमाने पर एचटीएमएल 5 ड्रैगलेव निकाल दिया गया




jquery html5 (18)

क्या बच्चे तत्व में खींचते समय ड्रैगलेव को फायरिंग से रोकना संभव है?

हाँ।

#drop * {pointer-events: none;}

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

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

यहां http://jsfiddle.net/pimvdb/HU6Mk/1/ हल करने वाला एक jsfiddle है

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

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

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

मेरी समस्या यह है कि उस तत्व के बच्चे तत्व को dragleave तत्व की 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 में काम करता है।


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

उम्मीद है कि यह काम करता है, यहाँ एक fiddle


अगर आप एचटीएमएल 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 है


आप इसे 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 घटनाओं पर मौजूद नहीं है, और मुझे लगता है कि आप क्रोम में काम कर रहे हैं क्योंकि आपका उदाहरण फ़ायरफ़ॉक्स में काम नहीं करता है। उपर्युक्त कोड के साथ एक संस्करण यहां लागू किया गया है।


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

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

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

इस समस्या को हल करने का "सही" तरीका ड्रॉप लक्ष्य के बाल तत्वों (जैसे @ एचडी के उत्तर में) पर सूचक घटनाओं को अक्षम करना है। यहां एक jsFiddle मैंने बनाया है जो इस तकनीक को प्रदर्शित करता है । दुर्भाग्यवश, यह IE11 से पहले इंटरनेट एक्सप्लोरर के संस्करणों में काम नहीं करता है, क्योंकि उन्होंने http://caniuse.com/pointer-events

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

अद्यतन करें:

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


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

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

और यहां यह क्रोम के लिए एक समाधान है:

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

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

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

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

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

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

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


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

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

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

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

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

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

(Obs .: ग्रेग पेटीट सलाह - आपको यह सुनिश्चित करना होगा कि मुखौटा सीमा सहित पूरे बॉक्स को होवर करे)


समस्या यह है कि जब माउस बच्चे के तत्व के सामने जाता है तो 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');
               }
           }

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

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


Just try to use the event.eventPhase. It will set to 2 (Event.AT_TARGET) only if the target ist entered, otherwise it is set to 3 (Event.BUBBLING_PHASE).

I'fe used the eventPhase to bind or unbind the dragleave Event.

$('.dropzone').on('dragenter', function(e) {

  if(e.eventPhase === Event.AT_TARGET) {

    $('.dropzone').addClass('drag-over');

    $('.dropzone').on('dragleave', function(e) {
      $('.dropzone').removeClass('drag-over');
    });

  }else{

    $('.dropzone').off('dragleave');

  }
})

Guido


You need to remove the pointer events for all child objects of the drag target.

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

use this code http://jsfiddle.net/HU6Mk/258/ :

$('#drop').bind({
         dragenter: function() {
             $(this).addClass('red');
         },

         dragleave: function(event) {
             var x = event.clientX, y = event.clientY,
                 elementMouseIsOver = document.elementFromPoint(x, y);
             if(!$(elementMouseIsOver).closest('.red').length) {
                 $(this).removeClass('red');
             }
        }
    });






drag-and-drop