HTML5 drablave срабатывает при наведении дочернего элемента

Проблема, с которой я сталкиваюсь, заключается в том, что событие 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>

со следующим JavaScript:

$('#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 Обновление: TL; DR, просмотрите CSS pointer-events: none;, как описано в @H.D. ниже, что работает в современных браузерах и IE11.

Ответ 1

Вам просто нужно держать счетчик ссылок, увеличивать его, когда вы получаете ловушку, уменьшаясь, когда вы получаете dragleave. Когда счетчик равен 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');
        }
    }
});

Примечание. В событии drop, reset counter to zero и очистите добавленный класс.

Вы можете запустить здесь

Ответ 2

Можно ли предотвратить включение dragleave при перетаскивании в дочерний элемент?

Да.

#drop * {pointer-events: none;}

Этот CSS, кажется, достаточно для Chrome.

При использовании его в Firefox #drop не должен иметь текстовые узлы напрямую (иначе есть странная проблема, когда элемент "оставьте это для себя" ) поэтому я предлагаю оставить его только с одним элементом (например, использовать div внутри #drop, чтобы поместить все внутри)

Здесь jsfiddle разрешает оригинальный вопрос (сломанный) пример.

Я также сделал упрощенную версию, выложенную из примера @Theodore Brown, но основанную только на этом CSS.

Не все браузеры используют этот CSS: http://caniuse.com/pointer-events

Увидев исходный код Facebook, я мог бы найти этот pointer-events: none; несколько раз, однако он, вероятно, использовался вместе с изящными отступниками деградации. По крайней мере, это так просто и решает проблему для многих сред.

Ответ 3

Здесь простейшее решение Cross-Browser (серьезно):

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

В нескольких словах вы создаете "маску" внутри dropzone с унаследованностью по ширине и высоте, абсолютной положением, которая будет отображаться только при запуске dragover.
Итак, после показа этой маски, вы можете сделать трюк, добавив другие dragleave и отбросить события на нем.

После того, как вы уйдете, вы просто снова спрячете маску.
Простые и без осложнений.

(Обьявление: совет Грега Петтита - вы должны быть уверены, что маска навешивает всю коробку, включая границу)

Ответ 4

"Правильный" способ решить эту проблему - отключить события указателя на дочерние элементы целевой цели (как в ответе @H.D.). Здесь создан jsFiddle, который демонстрирует эту технику. К сожалению, это не работает в версиях Internet Explorer до IE11, так как они не поддерживали события указателя.

К счастью, я смог придумать обходное решение, которое работает в старых версиях IE. В основном это связано с идентификацией и игнорированием событий dragleave, которые возникают при перетаскивании дочерних элементов. Поскольку событие dragenter запускается на дочерние узлы перед событием dragleave родителя, для каждого дочернего элемента node могут быть добавлены отдельные прослушиватели событий, которые добавляют или удаляют класс "игнорировать-перетаскивание-оставить" из целевой цели, Тогда целевой объект dragleave event droper может просто игнорировать вызовы, которые возникают, когда этот класс существует. Здесь jsFiddle демонстрирует это обходное решение. Он протестирован и работает в Chrome, Firefox и IE8 +.

Update:

Я создал jsFiddle, демонстрирующий комбинированное решение, используя обнаружение функции, где события указателя используются, если они поддерживаются (в настоящее время Chrome, Firefox и IE11), и браузер падает назад к добавлению событий к дочерним узлам, если поддержка событий указателя недоступна (IE8-10).

Ответ 5

Прошло довольно много времени после того, как задан этот вопрос, и предоставлено множество решений (включая уродливые хаки).

Мне удалось решить ту же самую проблему, которую я недавно получил благодаря ответу в этом ответе и подумал, что это может быть полезно для кого-то, кто выходит на эту страницу. Вся идея состоит в том, чтобы хранить evenet.target в ondrageenter каждый раз, когда он вызывается для любого из родительских или дочерних элементов. Затем в ondragleave проверьте, соответствует ли текущая цель (event.target) объекту, который вы сохранили в ondragenter.

Единственный случай, когда эти два совпадают, - это когда ваше перетаскивание покидает окно браузера.

Причина, по которой это работает, - это когда мышь покидает элемент (скажем el1) и входит в другой элемент (скажем el2), сначала вызывается el1.ondragenter, а затем el2.ondragleave. Только когда перетаскивание уходит/входит в окно браузера, event.target будет '' в el1.ondragenter и el2.ondragleave.

Вот мой рабочий образец. Я тестировал его на IE9 +, Chrome, Firefox и Safari.

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

При правильном стиле, я сделал, чтобы сделать внутренний div (# file-drop-area) намного больше всякий раз, когда файл перетаскивается на экран, чтобы пользователь мог легко отбросить файлы в нужное место.

Ответ 6

Проблема заключается в том, что событие 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');
               }
           }

Ответ 7

если вы используете HTML5, вы можете получить родительский clientRect:

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

Ответ 8

Очень простое решение - использовать свойство pointer-events CSS. Просто установите значение none на dragstart на каждом дочернем элементе. Эти элементы больше не будут вызывать события, связанные с мышью, поэтому они не поймают мышь над ними и, таким образом, не вызовут dragleave для родителя.

Не забудьте установить это свойство на auto, когда закончите перетаскивание;)

Ответ 9

Вы можете исправить это в Firefox с небольшим вдохновением из исходного кода 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');
        }
    }

}

К сожалению, это не работает в Chrome, потому что relatedTarget, похоже, не существует в событиях dragleave, и я предполагаю, что вы работая в Chrome, потому что ваш пример не работал в Firefox. Здесь реализована версия с указанным выше кодом.

Ответ 10

И вот оно, решение для Chrome:

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

Ответ 11

Это довольно простое решение работает для меня до сих пор, при условии, что ваше событие прикреплено к каждому элементу перетаскивания отдельно.

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

Ответ 12

Очень простое решение:

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

Ответ 13

Вот еще одно решение с использованием 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');
   }
}

Надеюсь, что это работает, здесь скрипка.

Ответ 14

Простым решением является добавление pointer-events: none правила css pointer-events: none к дочернему компоненту, чтобы предотвратить срабатывание 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>

Ответ 15

Я написал небольшую библиотеку под названием Dragster для решения этой конкретной проблемы, которая работает везде, кроме тихого бездействия в IE (который не поддерживает конструкторы событий DOM, но было бы довольно легко написать нечто подобное с помощью пользовательских событий jQuery)

Ответ 16

Не уверен, что этот перекрестный браузер, но я тестировал в Chrome и решает мою проблему:

Я хочу перетащить файл по всей странице, но мой dragleave запускается, когда я перетаскиваю дочерний элемент. Моим решением было посмотреть на 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;
});

Ответ 17

У меня была такая же проблема и я попытался использовать решение pk7s. Это сработало, но это может быть сделано немного лучше без каких-либо дополнительных элементов dom.

В основном идея такая же - добавьте лишний невидимый оверлей над областью сбрасывания. Только позволяет делать это без каких-либо дополнительных элементов dom. Вот часть, которую играют псевдоэлементы CSS.

Javascript

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

CSS

Это правило после создания создаёт полностью покрытый оверлей для области с возможностью изменения.

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

Вот полное решение: http://jsfiddle.net/F6GDq/8/

Я надеюсь, что это поможет любому, у кого есть такая же проблема.

Ответ 18

Просто проверьте, является ли перетаскиваемый элемент дочерним, если он есть, то не удаляйте класс стиля "dragover". Довольно просто и работает для меня:

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

Ответ 19

Я наткнулся на ту же проблему, и здесь мое решение, которое, я думаю, намного проще, чем выше. Я не уверен, что это кроссбраузер (может зависеть даже от порядка пузырьков)

Я буду использовать 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)

И об этом.:) это работает, потому что, хотя onEnter на дочерних огнях, прежде чем onLeave на родительском, мы задерживаем его, слегка меняя порядок, поэтому класс сначала удаляется, а затем снова извлекается после milisecond.

Ответ 20

Проведя так много часов, я получил это предложение, работающее точно так, как предполагалось. Я хотел бы дать реплику только тогда, когда файлы перетащили, а dragover, dragleave вызывает болезненные мерцания в браузере 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
});

Ответ 21

Альтернативное рабочее решение, немного проще.

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

Ответ 22

Я написал модуль перетаскивания под названием drip-drop, который исправляет это поведение отвращения, среди прочих. Если вы ищете хороший низкоуровневый модуль перетаскивания, который вы можете использовать в качестве основы для чего угодно (загрузка файлов, перетаскивание в приложении, перетаскивание из или из внешних источников), вы должны проверить это модуль:

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

Ответ 23

У меня была схожая проблема - мой код для скрытия dropzone в событии dragleave для тела был уволен, когда зависание дочерних элементов делало дропзону мерцанием в Google Chrome.

Я смог решить это, планируя функцию для скрытия dropzone вместо того, чтобы сразу ее вызвать. Затем, если запускается другое dragover или dragleave, вызов запланированной функции отменяется.

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

Ответ 24

Событие dragleave вызывается, когда указатель мыши покидает область перетаскивания целевого контейнера.

Это имеет большой смысл, поскольку во многих случаях может быть выброшен только родитель, а не потомки. Я думаю, что event.stopPropogation() должен был обработать этот случай, но кажется, что он не работает.

Вышеупомянутые решения, кажется, работают в большинстве случаев, но не работают в случае тех дочерних элементов, которые не поддерживают события dragenter/dragleave, такие как iframe.

1 обходной путь - проверить event.relatedTarget и убедиться, что он находится внутри контейнера, а затем проигнорировать событие dragleave, как я это сделал здесь:

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

Вы можете найти рабочую скрипку здесь !

Ответ 25

Вот еще один подход, основанный на сроках событий.

Событие dragenter, отправленное из дочернего элемента, может быть захвачено родительским элементом, и оно всегда встречается перед dragleave. Время между этими двумя событиями действительно короткое, короче любого возможного действия мыши. Итак, идея состоит в том, чтобы запомнить время, когда происходит событие dragenter и фильтровать события dragleave, "не слишком быстро" после...

Этот короткий пример работает с Chrome и Firefox:

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

Ответ 26

pimvdb..

Почему бы вам не попробовать использовать drop вместо dragleave. Это сработало для меня. надеюсь, что это решает вашу проблему.

Пожалуйста, проверьте jsFiddle: 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");
                 }
                });

Ответ 27

Вы можете использовать таймаут с флагом transitioning и прослушивать верхний элемент. dragenter/dragleave из дочерних событий будет пузыриться до контейнера.

Так как dragenter для дочернего элемента запускается перед dragleave контейнера, мы установим показ флага как переход на 1 мс... слушатель dragleave проверяет флаг перед тем, как 1 мс будет вверх.

Флаг будет истинным только при переходе к дочерним элементам и не будет истинным при переходе к родительскому элементу (контейнера)

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/

Ответ 28

Вам нужно удалить события указателя для всех дочерних объектов цели перетаскивания.

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

Ответ 29

используйте этот код 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');
             }
        }
    });

Ответ 30

Просто попробуйте использовать event.eventPhase. Он будет установлен на 2 (Event.AT_TARGET) только в том случае, если цель ist введена, в противном случае она установлена ​​в 3 (Event.BUBBLING_PHASE).

Я использовал eventPhase для привязки или отвязывания события dragleave.

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

  }
})

Гвидо