У меня проблема в том, что 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;
как описано в ответе @ HD ниже, который работает в современных браузерах и IE11.
dragleave
в этом случае все еще срабатывает.Ответы:
Вам просто нужно сохранить счетчик ссылок, увеличивать его, когда вы получаете перетаскивание, уменьшать, когда вы получаете перетаскивание. Когда счетчик на 0 - удалить класс.
Примечание. В событии сброса сбросьте счетчик до нуля и очистите добавленный класс.
Вы можете запустить его здесь
источник
pointer-events: none
детьми. Когда я начинаю перетаскивать, я добавляю класс, у которого есть это свойство, когда перетаскивание заканчивается, я удаляю класс. Хорошо работал на Safari и Chrome, но не на Firefox.dragenter
сохраняюevent.currentTarget
в новую переменнуюdragEnterTarget
. ПокаdragEnterTarget
установлено, я игнорирую дальнейшиеdragenter
события, потому что они от детей. Во всехdragleave
событиях я проверяюdragEnterTarget === event.target
. Если это false, событие будет проигнорировано, так как оно было запущено ребенком. Если это правда, я возвращаюсьdragEnterTarget
кundefined
.Да.
Этого CSS достаточно для Chrome.
При использовании его с Firefox, #drop не должно иметь текстовых узлов напрямую (иначе есть странная проблема, когда элемент «оставь это себе» ), поэтому я предлагаю оставить его только с одним элементом (например, использовать div внутри #drop положить все внутрь)
Вот jsfiddle, решающий оригинальный вопрос (сломанный) пример .
Я также сделал упрощенную версию разветвленной из примера @Theodore Brown, но основанную только на этом CSS.
Однако не во всех браузерах реализован этот CSS: http://caniuse.com/pointer-events
Увидев исходный код Facebook, я мог найти это
pointer-events: none;
несколько раз, но, вероятно, он использовался вместе с грациозным отказом от деградации. По крайней мере, это так просто и решает проблему для многих сред.источник
Здесь самое простое кросс-браузерное решение (серьезно):
jsfiddle <- попробуйте перетащить какой-нибудь файл в поле
Вы можете сделать что-то подобное:
В нескольких словах, вы создаете «маску» внутри зоны сброса, с унаследованной шириной и высотой, абсолютной позицией, которая будет отображаться только тогда, когда начинается драгувер.
Итак, после показа этой маски, вы можете сделать трюк, прикрепив к ней другие события Dragleave & Drop.
После ухода или падения вы просто снова прячете маску.
Просто и без осложнений.
(Обс .: совет Грега Петтита - Вы должны быть уверены, что маска нависает над всей коробкой, включая границы)
источник
Прошло довольно много времени после того, как этот вопрос был задан, и было предложено множество решений (включая некрасивые хаки).
Мне удалось решить ту же проблему, с которой я столкнулся недавно благодаря ответу в этом ответе, и подумал, что это может быть полезно для тех, кто заходит на эту страницу. Вся идея заключается в том, чтобы хранить
evenet.target
вondrageenter
каждый раз, когда он вызывается на любом из родительских или дочерних элементов. Затемondragleave
проверьте, соответствует ли текущий target (event.target
) объекту, в котором вы хранитеondragenter
.Единственный случай, когда эти два значения совпадают, это когда ваше перетаскивание покидает окно браузера.
Причина, по которой это работает нормально, заключается в том, что мышь покидает элемент (скажем
el1
) и вводит другой элемент (скажемel2
), сначалаel2.ondragenter
вызывается, а затемel1.ondragleave
. Только когда перетаскивание покидает / входит в окно браузера,event.target
будет''
в обоихel2.ondragenter
иel1.ondragleave
.Вот мой рабочий образец. Я проверил это на IE9 +, Chrome, Firefox и Safari.
А вот простая HTML-страница:
При правильном оформлении я сделал внутренний раздел (# file-drop-area) намного больше, когда файл перетаскивается на экран, чтобы пользователь мог легко поместить файлы в нужное место.
источник
==
over===
. Вы сравниваете ссылки на целевой объект события, поэтому===
тоже отлично работает.«Правильный» способ решить эту проблему - отключить события указателя на дочерних элементах цели удаления (как в ответе @ HD). Вот jsFiddle, который я создал, который демонстрирует эту технику . К сожалению, это не работает в версиях Internet Explorer до IE11, так как они не поддерживали события указателя .
К счастью, я был в состоянии придумать обходной путь , который делает работу в старых версиях IE. По сути, это включает в себя выявление и игнорирование
dragleave
событий, которые происходят при перетаскивании на дочерние элементы. Посколькуdragenter
событие вызывается на дочерних узлах доdragleave
события на родительском узле, к каждому дочернему узлу можно добавить отдельных прослушивателей событий, которые добавляют или удаляют класс ignore-drag-left из цели удаления. Тогдаdragleave
прослушиватель события целевой цели может просто игнорировать вызовы, которые происходят, когда этот класс существует. Вот jsFiddle, демонстрирующий этот обходной путь . Он протестирован и работает в Chrome, Firefox и IE8 +.Обновить:
Я создал jsFiddle, демонстрирующий комбинированное решение с использованием обнаружения функций, в котором используются события указателя, если они поддерживаются (в настоящее время Chrome, Firefox и IE11), и браузер возвращается к добавлению событий в дочерние узлы, если поддержка событий указателя недоступна (IE8 -10).
источник
dragleave
запуск события в Chrome, Firefox и IE11 +. Я также обновил свой другой обходной путь для поддержки IE8 и IE9, в дополнение к IE10. Намеренно, что эффект дропзоны добавляется только при перетаскивании ссылки «Перетащите меня». Другие могут свободно изменять это поведение по мере необходимости для поддержки своих вариантов использования.Проблема в том, что
dragleave
событие вызывается, когда мышь находится перед дочерним элементом.Я пробовал различные методы проверки, чтобы увидеть,
e.target
совпадает лиthis
элемент с элементом, но не смог добиться какого-либо улучшения.Способ, которым я исправил эту проблему, был немного взломан, но работает на 100%.
источник
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
.если вы используете HTML5, вы можете получить clientRect родительского:
Затем в parent.dragleave ():
вот jsfiddle
источник
border-radius
, перемещение указателя близко к углу фактически оставило бы элемент, но этот код все еще думал бы, что мы внутри (мы оставили элемент, но мы все еще находимся в ограничительном прямоугольнике). Тогдаdragleave
обработчик событий вообще не будет вызываться.Очень простое решение - использовать
pointer-events
свойство CSS . Просто установите его значениеnone
на dragstart для каждого дочернего элемента. Эти элементы больше не будут вызывать связанные с мышью события, поэтому они не будут ловить мышь над ними и, следовательно, не будут вызывать перетаскивание на родительском элементе .Не забудьте установить это свойство обратно
auto
при завершении перетаскивания;)источник
Это довольно простое решение работает для меня до сих пор, при условии, что ваше событие прикреплено к каждому элементу перетаскивания индивидуально.
источник
Очень простое решение:
источник
Вы можете исправить это в Firefox с небольшим вдохновением из исходного кода jQuery :
К сожалению, это не работает в Chrome, потому что,
relatedTarget
похоже, не существует вdragleave
событиях, и я предполагаю, что вы работаете в Chrome, потому что ваш пример не работал в Firefox. Вот версия с реализованным выше кодом.источник
И вот оно, решение для Chrome:
источник
border-radius
как я объяснил в своем комментарии к ответу @ azlar выше.Вот еще одно решение с использованием document.elementFromPoint:
Надеюсь, что это работает, вот скрипка .
источник
event.clientX, event.clientY
вместо этого, так как они относятся к области просмотра, а не к странице. Я надеюсь, что это помогает другой потерянной душе там.Простое решение - добавить правило css
pointer-events: none
в дочерний компонент, чтобы предотвратить срабатывание триггераondragleave
. Смотрите пример:источник
dragged = event.target;clone = dragged.cloneNode();clone.style.pointerEvents = 'none';
Не уверен, что это кросс-браузер, но я тестировал в Chrome, и это решает мою проблему:
Я хочу перетащить файл на всю страницу, но моя перетаскивание срабатывает, когда я перетаскиваю дочерний элемент. Мое исправление было посмотреть на х и у мыши:
У меня есть div, который перекрывает всю мою страницу, когда страница загружается, я скрываю это.
когда вы перетаскиваете документ, я показываю его, а когда вы опускаете родительский элемент, он обрабатывает его, а когда вы покидаете родительский элемент, я проверяю x и y.
источник
Я написал небольшую библиотеку Dragster для решения этой конкретной проблемы, которая работает везде, кроме тихого бездействия в IE (который не поддерживает конструкторы событий DOM, но было бы довольно легко написать нечто подобное с помощью пользовательских событий jQuery)
источник
У меня возникла та же проблема, и я попытался использовать решение pk7s. Это сработало, но можно было бы сделать немного лучше без каких-либо дополнительных элементов DOM.
По сути, идея та же самая - добавить дополнительное невидимое наложение поверх области, которую можно опустить. Только давайте делать это без каких-либо дополнительных элементов DOM. Вот часть, где псевдоэлементы CSS вступают в игру.
Javascript
CSS
Это правило после создания создаст полностью покрытый оверлей для области, которую можно сбросить.
Вот полное решение: http://jsfiddle.net/F6GDq/8/
Я надеюсь, что это поможет любому с той же проблемой.
источник
Просто проверьте, является ли перетаскиваемый элемент дочерним, если это так, то не удаляйте свой класс стиля dragover. Довольно просто и работает для меня:
источник
Я столкнулся с той же проблемой, и вот мое решение, которое, я думаю, намного проще, чем выше. Я не уверен, что это кроссбраузер (может зависеть даже от порядка пузырьков)
Я буду использовать jQuery для простоты, но решение должно быть независимым от фреймворка.
Событие переходит к родителю в любом случае так:
Мы прикрепляем события
И это все. :) это работает, потому что хотя onEnter на дочернем объекте срабатывает перед onLeave на родительском, мы немного задерживаем его, изменяя порядок, поэтому сначала класс удаляется, а затем повторно вызывается через миллисекунду.
источник
Я написал модуль drag-and-drop под названием drip-drop, который, среди прочего, исправляет это странное поведение. Если вы ищете хороший низкоуровневый модуль перетаскивания, который вы можете использовать в качестве основы для чего-либо (загрузка файлов, перетаскивание в приложении, перетаскивание из или на внешние источники), вам следует проверить это модуль из:
https://github.com/fresheneesz/drip-drop
Вот как вы будете делать то, что вы пытаетесь сделать в капельном режиме:
Чтобы сделать это без библиотеки, метод счетчика - это то, что я использовал в капельном режиме, поскольку в ответе с наивысшим рейтингом пропущены важные шаги, которые могут привести к поломке всего, кроме первой капли. Вот как это сделать правильно:
источник
Альтернативное рабочее решение, немного проще.
источник
clientX
выше 0, когда мышь находится за пределами поля. Конечно, мои элементыposition:absolute
Потратив так много часов, я понял, что это предложение работает точно так, как задумано. Я хотел предоставить сигнал только тогда, когда файлы перетаскивались, а при перетаскивании документа, dragleave вызывал болезненные мерцания в браузере Chrome.
Вот как я это решил, также добавив подходящие подсказки для пользователя.
источник
У меня была похожая проблема - мой код для скрытия dropzone на событии dragleave для body был запущен одновременно, когда парящие дочерние элементы вызывали мерцание dropzone в Google Chrome.
Я смог решить эту проблему, запланировав функцию скрытия дропзоны, а не вызывая ее сразу. Затем, если запускается другой драговер или драглэйв, запланированный вызов функции отменяется.
источник
« DragLeave » событие вызывается , когда указатель мыши покидает зону перетаскивания целевого контейнера.
Это имеет большой смысл, так как во многих случаях может сбрасываться только родитель, а не потомки. Я думаю, что event.stopPropogation () должен был обработать этот случай, но кажется, что он не работает.
Вышеупомянутые решения, кажется, работают в большинстве случаев, но не работают в случае тех дочерних элементов, которые не поддерживают события dragenter / dragleave , такие как iframe .
1 обходной путь - проверить event.relatedTarget и убедиться, что он находится внутри контейнера, а затем проигнорировать событие dragleave, как я это сделал здесь:
Вы можете найти рабочую скрипку здесь !
источник
Решено ..!
Объявите любой массив для ex:
Не нужно беспокоиться о дочерних элементах.
источник
Я много боролся с этим, даже после прочтения всех этих ответов, и подумал, что могу поделиться с вами своим решением, потому что я подумал, что это может быть один из более простых подходов, хотя и несколько другой. Я думал о том, чтобы просто
dragleave
полностью исключить прослушиватель событий и кодировать поведение dragleave при каждом новом событии dragenter, в то же время следя за тем, чтобы события dragenter не запускались без необходимости.В моем примере ниже у меня есть таблица, где я хочу иметь возможность обмениваться содержимым строк таблицы друг с другом с помощью API перетаскивания. В
dragenter
, класс CSS должен быть добавлен к строке элемента , в котором вы сейчас тащит свой элемент, чтобы выделить его, и наdragleave
этот класс должен быть удален.Пример:
Очень простая таблица HTML:
А функция DragEnter обработчик события добавляется на каждую ячейку таблицы (кроме
dragstart
,dragover
,drop
иdragend
обработчики, которые не являются специфическими для этого вопроса, поэтому не скопированные здесь):В коде остались очень простые комментарии, так что этот код подходит и для начинающих. Надеюсь, это поможет вам! Обратите внимание, что вам, конечно, нужно добавить всех прослушивателей событий, о которых я упоминал выше, в каждую ячейку таблицы, чтобы это работало.
источник
Вот еще один подход, основанный на времени событий.
dragenter
Событие отправляется из дочернего элемента может быть захвачено родительским элементом , и это всегда происходит передdragleave
. Время между этими двумя событиями действительно короткое, короче, чем любое возможное действие мыши. Таким образом, идея состоит в том, чтобы запомнить время, когдаdragenter
происходит, и отфильтроватьdragleave
события, которые происходят "не слишком быстро" после ...Этот короткий пример работает на Chrome и Firefox:
источник
pimvdb ..
Почему бы вам не попробовать использовать drop вместо dragleave . Это сработало для меня. надеюсь, что это решит вашу проблему.
Пожалуйста, проверьте jsFiddle: http://jsfiddle.net/HU6Mk/118/
источник
Вы можете использовать тайм-аут с
transitioning
флагом и прослушивать верхний элемент.dragenter
/dragleave
от дочерних событий будет всплывать до контейнера.Так
dragenter
как дочерний элемент запускается передdragleave
контейнером, мы установим флаг show как переходный на 1 мс ...dragleave
слушатель проверит флаг на наличие 1 мс.Флаг будет истинным только при переходах к дочерним элементам и не будет истинным при переходе к родительскому элементу (контейнера)
jsfiddle: http://jsfiddle.net/ilovett/U7mJj/
источник
Вам необходимо удалить события указателя для всех дочерних объектов цели перетаскивания.
источник