Przegląd
Mam następującą strukturę HTML i dołączyłem zdarzenia dragenter
i dragleave
do <div id="dropzone">
elementu.
<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>
Problem
Kiedy przeciągam plik na <div id="dropzone">
, dragenter
zdarzenie jest uruchamiane zgodnie z oczekiwaniami. Jednak, gdy poruszam myszką na element dziecięcej, takich jak <div id="drag-n-drop">
The dragenter
zdarzenie jest opalane dla <div id="drag-n-drop">
elementu, a następnie dragleave
zdarzenie jest opalane dla <div id="dropzone">
elementu.
Jeśli <div id="dropzone">
ponownie najeżdżam na element, dragenter
zdarzenie jest ponownie uruchamiane, co jest fajne, ale potem dragleave
zdarzenie jest uruchamiane dla elementu podrzędnego, który właśnie pozostał, więc removeClass
instrukcja jest wykonywana, co nie jest fajne.
To zachowanie jest problematyczne z 2 powodów:
Dołączam tylko
dragenter
&dragleave
do tego,<div id="dropzone">
więc nie rozumiem, dlaczego elementy dziecięce mają również dołączone te zdarzenia.Ciągle przeciągam po
<div id="dropzone">
elemencie, najeżdżając na jego elementy podrzędne, więc nie chcędragleave
strzelać!
jsFiddle
Oto jsFiddle do majstrowania przy: http://jsfiddle.net/yYF3S/2/
Pytanie
Więc ... jak mogę to zrobić tak, że kiedy przeciągam plik po <div id="dropzone">
elemencie, dragleave
nie uruchamia się, nawet jeśli przeciągam po elementach podrzędnych ... powinien uruchamiać się tylko wtedy, gdy opuszczam <div id="dropzone">
element .. . Najechanie kursorem / przeciągnięcie po dowolnym miejscu w granicach elementu nie powinno wywołać dragleave
zdarzenia.
Potrzebuję tego, aby był kompatybilny z różnymi przeglądarkami, przynajmniej w przeglądarkach obsługujących przeciąganie i upuszczanie HTML5, więc ta odpowiedź nie jest wystarczająca.
Wygląda na to, że Google i Dropbox to rozgryzły, ale ich kod źródłowy jest zminimalizowany / złożony, więc nie byłem w stanie tego rozgryźć na podstawie ich implementacji.
e.stopPropagation();
Odpowiedzi:
Jeśli nie musisz wiązać zdarzeń z elementami podrzędnymi, zawsze możesz użyć właściwości pointer-events.
źródło
:hover
stylów ani funkcji obsługi zdarzeń kliknięcia). Jeśli chcesz zachować te wydarzenia, oto inne obejście, którego używam: bensmithett.github.io/dragster.dropzone * {pointer-events: none;}
$('.element').addClass('dragging-over')
do elementu, nad którym przeciągasz, i$('.element').removeClass('dragging-over')
kiedy przeciągasz. Następnie w swoim CSS możesz mieć.element.dragging-over * { pointer-events: none; }
. To usuwa zdarzenia wskaźnika ze wszystkich elementów podrzędnych tylko podczas przeciągania.W końcu znalazłem rozwiązanie, z którego jestem zadowolony. Właściwie znalazłem kilka sposobów robienia tego, co chcę, ale żaden nie był tak skuteczny jak obecne rozwiązanie ... w jednym rozwiązaniu doświadczyłem częstego migotania w wyniku dodania / usunięcia obramowania
#dropzone
elementu ... w innym obramowanie nigdy nie został usunięty, jeśli najedziesz kursorem poza przeglądarkę.W każdym razie, moim najlepszym rozwiązaniem jest to:
Działa to całkiem nieźle, ale problemy pojawiły się w Firefoksie, ponieważ Firefox wywoływał podwójnie
dragenter
więc mój licznik był wyłączony. Niemniej jednak jest to niezbyt eleganckie rozwiązanie.Potem natknąłem się na to pytanie: jak wykryć zdarzenie dragleave w Firefoksie podczas przeciągania poza okno
Więc wziąłem odpowiedź i zastosowałem ją do mojej sytuacji:
To jest przejrzyste i eleganckie i wydaje się działać w każdej przeglądarce, którą do tej pory testowałem (jeszcze nie testowałem IE).
źródło
stopPropagation()
ipreventDefault()
jest preferowany. Upuściłbymreturn false
.To trochę brzydkie, ale działa do cholery! ...
W module obsługi „dragenter” zapisz zdarzenie.target (w zmiennej wewnątrz twojego zamknięcia lub czymkolwiek), a następnie w module obsługi „dragleave” uruchom kod tylko wtedy, gdy event.target === ten, który zapisałeś.
Jeśli twój 'dragenter' odpala, kiedy tego nie chcesz (np. Kiedy wchodzi po opuszczeniu elementów potomnych), to ostatnim razem, gdy odpala, zanim mysz opuści rodzica, jest na rodzicu, więc rodzic zawsze będzie ostatni „dragenter” przed zamierzonym „dragleave”.
źródło
Na początku zgodziłem się z ludźmi, którzy odrzucili to
pointer-events: none
podejście. Ale wtedy zadałem sobie pytanie:W moim przypadku wiele rzeczy dzieje się u dzieci, np. Najechanie kursorem, aby wyświetlić przyciski do dodatkowych działań, edycja bezpośrednia itp. Jednak nic z tego nie jest konieczne ani nawet pożądane podczas przeciągania.
W moim przypadku używam czegoś takiego, aby selektywnie wyłączać zdarzenia wskaźnika dla wszystkich węzłów podrzędnych kontenera nadrzędnego:
Użyj swojego ulubionego podejścia, aby dodać / usunąć klasę
dragging-in-progress
w obsłudze zdarzeńdragEnter
/dragLeave
, tak jak zrobiłem lub zrobiłem to samo wdragStart
, et. glin.źródło
dragstart
wydarzenia i usuń jądragend
.Wygląda na to, że jest to błąd przeglądarki Chrome.
Jedynym obejściem, jakie mogłem wymyślić, było utworzenie przezroczystego elementu nakładki do przechwytywania wydarzeń: http://jsfiddle.net/yYF3S/10/
JS :
HTML :
źródło
Problem w tym, że twoje elementy w dropzone są oczywiście częścią dropzone i kiedy wchodzisz do dzieci, opuszczasz rodzica. Rozwiązanie tego nie jest łatwe. Możesz spróbować dodać wydarzenia do dzieci, dodając ponownie klasę do rodzica.
Twoje wydarzenia będą nadal uruchamiane wiele razy, ale nikt nie zobaczy.
// Edycja: użyj zdarzenia dragmove, aby trwale nadpisać zdarzenie dragleave:
Zdefiniuj zdarzenie dragleave tylko dla strefy zrzutu.
źródło
dragleave
... kiedy zostawiam dziecko, mogę nadal być z rodzicem,#dropzone
ale to nie uruchomidragenter
wydarzenia ponownie :(dragleave
zdarzenie jest uruchamiane dla elementu podrzędnego, który właśnie pozostał, więc ponownieremoveClass
instrukcja jest wykonywanadragleave
tylko dla#dropzone
... gdybym mógł, nie miałbym tego problemu.Jak Benr wspomniał w tej odpowiedzi , możesz zapobiec uruchamianiu przez węzły potomne zdarzeń, ale jeśli chcesz powiązać niektóre zdarzenia, zrób to:
I dodaj to do swojego kodu JS:
źródło
Jeśli używasz jQuery, sprawdź to: https://github.com/dancork/jquery.event.dragout
To naprawdę niesamowite.
EDYCJA: właściwie nie sądzę, że jest to zależne od jQuery, prawdopodobnie możesz po prostu użyć kodu nawet bez niego.
źródło
dragleave
mimo że nie opuściłem nadrzędnej strefy zrzutu.dragout
było to jedyne rozwiązanie, które u mnie zadziałało.@hristo Mam dużo bardziej eleganckie rozwiązanie. Sprawdź, czy możesz tego użyć.
Twój wysiłek nie poszedł jednak na marne. Na początku udało mi się użyć twojego, ale miałem inne problemy w FF, Chrome. Po spędzeniu tylu godzin sugestia zadziałała dokładnie tak, jak powinna.
Oto jak wygląda implementacja. Skorzystałem również z wizualnych wskazówek, aby poprawnie poprowadzić użytkowników po strefie zrzutu.
źródło
var dropZoneHideDelay=70, dropZoneVisible=true;
dropZoneHideDelay, dropZoneVisible
są potrzebne w dwóch'on'
zdarzeniach dotyczących dokumentów w mojej implementacji.Moje dwa centy: Ukryj warstwę nad strefą upuszczania, a następnie pokaż ją po przeciągnięciu i wyceluj w dragleave.
Demo: https://jsfiddle.net/t6q4shat/
HTML
CSS
JS
źródło
Więc dla mnie to podejście
pointer-events: none;
nie zadziałało zbyt dobrze ... Więc oto moje alternatywne rozwiązanie:W ten sposób nie jest to możliwe dla
dragleave
rodzica (na dziecko) lubdragover
element podrzędny. mam nadzieję że to pomoże :)* Klasa „.active”, którą dodaję, gdy ja
dragenter
lubdragleave
. Ale jeśli pracujesz bez tego, po prostu zostaw klasę.źródło
Super prosta, szybka poprawka, nie testowana szeroko, ale teraz działa w Chrome.
Przepraszam za Coffeescript.
To naprawia błąd migotania Chrome, a przynajmniej jego permutację, która powodowała problemy.
źródło
Tę odpowiedź można znaleźć tutaj:
Dragleave HTML5 został uruchomiony po najechaniu na element podrzędny
źródło
Moja wersja:
W tym układzie:
Zrobiłem zrzut klas element
e.target
,e.currentTarget
,e.relatedTarget
zarównodragover
idragleave
wydarzeń.Pokazało mi, że opuszczając blok rodzica (
.dropzone
)e.relatedTarget
nie jest dzieckiem tego bloku, więc wiem, że jestem poza strefą zrzutu.źródło
Tutaj jedno z najprostszych rozwiązań ● ︿ ●
Spójrz na te skrzypce <- spróbuj przeciągnąć jakiś plik do pudełka
Możesz zrobić coś takiego:
Dzięki temu powinieneś już wiedzieć, co się tutaj dzieje.
Po prostu spójrz na skrzypce, wiesz.
źródło
Miałem podobny problem i naprawiłem go w ten sposób:
Problem: funkcja drop (ev) jest uruchamiana, gdy użytkownik upuści element w „drop zone” (element ul), ale niestety także wtedy, gdy element zostanie upuszczony w jednym ze swoich elementów potomnych (element li).
Poprawka:
źródło
Próbowałem to zaimplementować samodzielnie dla pola przesyłania plików, w którym kolor pudełka zmieniałby się, gdy użytkownicy przeciągali plik w przestrzeń.
Znalazłem rozwiązanie, które jest fajną mieszanką JavaScript i CSS. Powiedzmy, że masz strefę zrzutu
div
z identyfikatorem#drop
. Dodaj to do swojego Javascript:Następnie dodaj to do swojego CSS, aby dezaktywować wszystkie dzieci będą klasy
.inactive
:W ten sposób elementy potomne będą nieaktywne tak długo, jak długo użytkownik będzie przeciągał element po ramce.
źródło
Nie czułem się usatysfakcjonowany żadnym z przedstawionych tutaj obejść, ponieważ nie chcę stracić kontroli nad elementami podrzędnymi.
Więc użyłem innego podejścia logicznego, tłumacząc to na wtyczkę jQuery o nazwie jquery-draghandler . Absolutnie nie manipuluje DOM, gwarantując wysoką wydajność. Jego użycie jest proste:
Bezbłędnie rozwiązuje problem, nie naruszając żadnej funkcjonalności DOM.
Pobierz, szczegóły i wyjaśnienia dotyczące repozytorium Git .
źródło
frame
s, a twój element znajduje się na jego granicy. W takim razie nie proponuję takiego podejścia.Właściwie podoba mi się to, co widzę https://github.com/lolmaus/jquery.dragbetter/ale chciałem podzielić się możliwą alternatywą. Moją ogólną strategią było zastosowanie stylu tła do strefy upuszczenia (a nie jej elementów potomnych) podczas przeciągania do niej lub dowolnego jej elementu podrzędnego (za pomocą bąbelków). Następnie usuwam styl podczas przeciągania strefy zrzutu. Pomysł polegał na tym, że przenosząc się do dziecka, nawet jeśli usunę styl ze strefy upuszczenia, gdy ją opuszczę (ogień dragleave), po prostu ponownie zastosuję styl do strefy upuszczenia rodzica po przeciągnięciu dowolnego dziecka. Problem polega oczywiście na tym, że podczas przechodzenia ze strefy upuszczania do strefy podrzędnej dragenter zostaje wystrzelony na dziecko przed skokiem dragleave, więc moje style zostały zastosowane poza kolejnością. Rozwiązaniem dla mnie było użycie licznika czasu, aby zmusić zdarzenie dragenter z powrotem do kolejki wiadomości, co pozwoliło mi przetworzyć je PO DRagleave. Użyłem zamknięcia, aby uzyskać dostęp do zdarzenia w wywołaniu zwrotnym zegara.
Wygląda na to, że działa w Chrome, czyli Firefoxie i działa niezależnie od liczby dzieci w strefie zrzutu. Jestem trochę zaniepokojony limitem czasu gwarantującym ponowne sekwencjonowanie wydarzeń, ale wydaje się, że działa całkiem dobrze w moim przypadku użycia.
źródło
Próbowałem to zaimplementować samodzielnie i nie chciałem też Jquery ani żadnej wtyczki.
Chciałem obsłużyć przesyłanie pliku, w następujący sposób uznany za najlepszy dla mnie:
Struktura plików:
--- / uploads {uploads directory}
--- /js/slyupload.js {plik javascript.}
--- index.php
--- upload.php
--- styles.css {tylko trochę stylizacji ...}
Kod HTML:
To jest załączony plik JavaScript: „js / slyupload.js”
CSS:
źródło
Przepraszam, że to javascript, a nie jquery, ale dla mnie jest to najbardziej logiczny sposób rozwiązania tego problemu. Przeglądarka powinna wywołać dropleave (poprzedniego elementu) przed dropenter (nowego elementu, ponieważ coś nie może wprowadzić czegoś innego przed opuszczeniem pierwszej rzeczy, nie rozumiem, dlaczego to zrobili! Więc wystarczy opóźnić) de dropleave w ten sposób:
A dropenter nastąpi po dropleave, to wszystko!
źródło
Użyj
greedy : true
do dziecka jako funkcjidroppable
. Następnie rozpocznij tylko zdarzenie kliknięte na pierwszej warstwie.źródło