jquery html - 在拖動子元素時,父元素的“dragleave”會觸發




11 Answers

如果您不需要將事件綁定到子元素,則始終可以使用pointer-events屬性。

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

概觀

我有以下HTML結構,並將dragenterdragleave事件附加到<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">類的子元素上時,會為<div id="drag-n-drop">元素觸發dragenter事件,然後為<div id="dropzone">元素dragleave事件。

如果我再次將鼠標懸停在<div id="dropzone">元素上,則會再次觸發dragenter事件,這很酷,但隨後會為剛剛離開的子元素觸發dragleave事件,因此會執行removeClass指令,即不酷。

這種行為是有問題的,原因有二:

  1. 我只是將dragenterdragleave<div id="dropzone">所以我不明白為什麼兒童元素也附加了這些事件。

  2. 我仍然在將dragleave懸停在其<div id="dropzone">元素上時拖動它,所以我不想讓dragleave發射!

的jsfiddle

這裡有一個jsFiddle來修補: http://jsfiddle.net/yYF3S/2/ : http://jsfiddle.net/yYF3S/2/

所以...我怎麼能這樣做,當我通過<div id="dropzone">元素拖動文件時,即使拖動dragleave元素, dragleave也不會觸發......它應該只有在離開<div id="dropzone">元素時才會觸發dragleave在元素邊界內的任何位置懸停/拖動都不觸發dragleave事件。

我需要這是跨瀏覽器兼容的,至少在支持HTML5拖放的瀏覽器中,所以這個答案是不夠的。

看起來谷歌和Dropbox已經知道了這一點,但是他們的源代碼被縮小/複雜了,所以我沒有能夠從他們的實現中弄清楚這一點。




這有點醜,但它的作用不好!

在你的'dragenter'處理程序中存儲event.target(在你的閉包中的一個變量中,或其他),然後在你的'dragleave'處理程序中,只有在你存儲的event.target ===時才會激活你的代碼。

如果你的'dragenter'在你不想要的時候觸發(即它在離開子元素後進入),那麼它最後一次在鼠標離開父元素之前觸發,它在父元素上,所以父元素總是打算在'dragleave'之前的最終'dragenter'。

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

}());



這似乎是一個Chrome錯誤。

我能想到的唯一解決方法是創建一個透明的覆蓋元素來捕獲您的事件: http://jsfiddle.net/yYF3S/10/ : http://jsfiddle.net/yYF3S/10/

JS

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



如果您使用的是jQuery,請查看: https://github.com/dancork/jquery.event.dragouthttps://github.com/dancork/jquery.event.dragout

這真的很棒。

創建特殊事件來處理真正的dragleave功能。

HTML5 dragleave事件更像mouseout。 這個插件是為了在拖動時復制鼠標風格功能而創建的。

用法示例:

$('#myelement')。on('dragout',function(event){// YOUR CODE});

編輯:實際上,我不認為它依賴於jQuery,你甚至可以使用代碼,即使沒有它。




@hristo我有一個更優雅的解決方案。 檢查,如果這是你可以使用的東西。

畢竟你的努力沒有被浪費掉。 我設法首先使用你的,但在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
});



所以對我來說,這個方法pointer-events: none; 工作不太好...所以這是我的替代解決方案:

    #dropzone {
        position: relative;
    }

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

這樣就不可能dragleave父母(在小孩dragleave )或dragover子元素。 希望這可以幫助 :)

*當我dragleavedragleave時,我添加的'.active'類。 但是,如果你沒有這樣的工作,只能離開這個班。




在這裡,最簡單的解決方案之一●︿●

看看這個fiddle < - 嘗試拖動框內的一些文件

你可以做這樣的事情:

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

由此你應該已經知道這裡發生了什麼。
你知道,看看小提琴吧。




我試圖自己實現一個文件上傳框,當用戶將文件拖入空間時,框的顏色會發生變化。

我找到了一個Javascript和CSS的完美結合的解決方案。 假設你有一個可#drop區域,其中id為#drop 。 將此添加到您的Javascript中:

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

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

然後,將此添加到您的CSS,以禁用所有的孩子將類.inactive

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

因此,只要用戶在框上拖動元素,子元素將處於不活動狀態。




我試圖自己實現這一點,我不想要Jquery或任何插件......我想以我認為最適合的方式處理文件上傳......所以這是我的解決方案......而且它的工作原理! !...

文件結構

--- / uploads {上傳目錄}

--- /js/slyupload.js {javascript文件。}

--- index.php

--- upload.php

--- styles.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>

然後這是附加的Javascript文件::'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));

現在的CSS,一點點樣式...

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




這個答案可以在這裡找到:

懸停子元素時會觸發HTML5 dragleave

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



使用greedy : true對於孩子來說,這是droppable的功能。 然後在第一層開始僅點擊事件。




Related

jquery html5 javascript-events file-upload drag-and-drop