Jak mogę wykryć, że użytkownik anuluje dane wejściowe pliku za pomocą danych wejściowych w formacie html?
onChange pozwala mi wykryć, kiedy wybierają plik, ale chciałbym również wiedzieć, kiedy anulują (zamknij okno dialogowe wyboru pliku bez wybierania czegokolwiek).
e.target.files
Odpowiedzi:
Chociaż nie jest to bezpośrednie rozwiązanie, a także złe, ponieważ (o ile testowałem) działa tylko z ogniskiem (wymagającym dość ograniczającego blokowania zdarzeń), możesz to osiągnąć, wykonując następujące czynności:
Fajne w tym jest to, że możesz dołączyć / odłączyć go na czas ze zdarzeniem pliku, a także wydaje się, że działa dobrze z ukrytymi danymi wejściowymi (zdecydowana korzyść, jeśli używasz wizualnego obejścia dla kiepskiego domyślnego typu wejścia = '' plik'). Następnie wystarczy dowiedzieć się, czy wartość wejściowa uległa zmianie.
Przykład:
Zobacz to w akcji: http://jsfiddle.net/Shiboe/yuK3r/6/
Niestety, wygląda na to, że działa tylko w przeglądarkach webkit. Może ktoś inny może wymyślić rozwiązanie Firefox / IE
źródło
addEventListener("focus",fn,{once: true})
. Jednak nie mogłem go w ogóle uruchomić za pomocądocument.body.addEventListener
… nie wiem dlaczego. Zamiast tego uzyskałem ten sam wynik zwindow.addEventListener
.mousemove
wydarzenia nawindow.document
w uzupełnieniu do słuchaniafocus
nawindow
zdaje się wszędzie działa (przynajmniej w nowoczesnych przeglądarkach, nie dbam o wrakach przeszłość dekady). Zasadniczo do tego zadania można użyć dowolnego zdarzenia interakcji, które jest blokowane przez otwarte okno dialogowe otwierania pliku.Nie możesz.
Wynik okna dialogowego pliku nie jest widoczny dla przeglądarki.
źródło
change
zdarzenie nie jest wysyłane.change
zdarzenie nie zostanie z tego powodu wywołane.Więc rzucę kapelusz na to pytanie, ponieważ wymyśliłem nowatorskie rozwiązanie. Mam progresywną aplikację internetową, która umożliwia użytkownikom robienie zdjęć i filmów oraz przesyłanie ich. Używamy WebRTC, gdy jest to możliwe, ale wracamy do selektorów plików HTML5 dla urządzeń z mniejszą obsługą * kaszel Safari kaszel *. Jeśli pracujesz konkretnie na mobilnej aplikacji internetowej na Androida / iOS, która używa natywnego aparatu do bezpośredniego przechwytywania zdjęć / filmów, jest to najlepsze rozwiązanie, z którym się spotkałem.
Sedno tego problemu polega na tym, że kiedy strona się ładuje, to
file
jestnull
, ale kiedy użytkownik otworzy okno dialogowe i naciśnie "Anuluj",file
nadal jestnull
, więc nie zmienił się, więc nie jest wyzwalane żadne zdarzenie "zmień". W przypadku komputerów stacjonarnych nie jest to takie złe, ponieważ większość interfejsów użytkownika komputerów stacjonarnych nie jest zależnych od wiedzy, kiedy wywoływane jest anulowanie, ale mobilne interfejsy użytkownika, które uruchamiają aparat w celu zrobienia zdjęcia / wideo, są bardzo zależne od wiedzy, kiedy naciśnięto anulowanie.Początkowo użyłem
document.body.onfocus
zdarzenia do wykrycia, kiedy użytkownik wrócił z selektora plików i działało to na większości urządzeń, ale iOS 11.3 zepsuł je, ponieważ to zdarzenie nie jest wyzwalane.Pojęcie
Moim rozwiązaniem jest * drżenie *, aby zmierzyć taktowanie procesora w celu określenia, czy strona jest obecnie na pierwszym planie, czy w tle. Na urządzeniach mobilnych czas przetwarzania jest przypisywany aplikacji znajdującej się obecnie na pierwszym planie. Kiedy kamera jest widoczna, kradnie czas procesora i pozbawia przeglądarkę priorytetów. Wszystko, co musimy zrobić, to zmierzyć, ile czasu przetwarzania zajmuje nasza strona, po uruchomieniu aparatu nasz dostępny czas drastycznie spadnie. Kiedy kamera jest zamknięta (anulowana lub w inny sposób), nasz dostępny czas rośnie.
Realizacja
Możemy zmierzyć taktowanie procesora za pomocą
setTimeout()
wywołania wywołania zwrotnego w X milisekund, a następnie zmierzyć, ile czasu zajęło jego rzeczywiste wywołanie. Przeglądarka nigdy nie wywoła go dokładnie po X milisekundach, ale jeśli jest to rozsądne blisko, to musimy być na pierwszym planie. Jeśli przeglądarka jest bardzo daleko (ponad 10x wolniej niż żądano), musimy znajdować się w tle. Podstawowa implementacja tego jest następująca:Przetestowałem to na najnowszej wersji iOS i Androida, wywołując natywną kamerę, ustawiając atrybuty
<input />
elementu.To działa o wiele lepiej, niż się spodziewałem. Uruchamia 10 prób, żądając wywołania licznika czasu w ciągu 25 milisekund. Następnie mierzy, ile czasu faktycznie zajęło wywołanie, a jeśli średnia z 10 prób jest mniejsza niż 50 milisekund, zakładamy, że musimy być na pierwszym planie, a kamera zniknęła. Jeśli jest dłuższy niż 50 milisekund, to nadal musimy być w tle i powinniśmy nadal czekać.
Kilka dodatkowych szczegółów
Użyłem
setTimeout()
raczej niżsetInterval()
dlatego, że ta ostatnia może kolejkować wiele wywołań, które są wykonywane natychmiast po sobie. Może to drastycznie zwiększyć szum w naszych danych, więc utknąłem przysetTimeout()
tym, mimo że jest to trochę bardziej skomplikowane.Te konkretne liczby działały dobrze dla mnie, chociaż widziałem przynajmniej raz przypadek, w którym odrzucenie kamery zostało wykryte przedwcześnie. Uważam, że dzieje się tak, ponieważ kamera może się otwierać powoli, a urządzenie może przeprowadzić 10 prób, zanim faktycznie przejdzie w tło. Dodanie kolejnych prób lub odczekanie około 25-50 milisekund przed uruchomieniem tej funkcji może być obejściem tego problemu.
Pulpit
Niestety, to nie działa tak naprawdę w przeglądarkach komputerowych. W teorii ta sama sztuczka jest możliwa, ponieważ priorytetyzują bieżącą stronę względem stron w tle. Jednak wiele komputerów ma wystarczającą ilość zasobów, aby strona działała z pełną prędkością, nawet w tle, więc ta strategia tak naprawdę nie działa w praktyce.
Alternatywne rozwiązania
Jednym z alternatywnych rozwiązań, o których niewiele osób wspomina, było kpienie z pliku
FileList
. Zaczynamynull
od,<input />
a następnie, jeśli użytkownik otworzy kamerę i anuluje, donull
którego wróci , co nie jest zmianą i żadne zdarzenie nie zostanie wywołane. Jednym z rozwiązań byłoby przypisanie fikcyjnego pliku do<input />
początku strony, dlatego ustawienie nanull
byłoby zmianą, która wywołałaby odpowiednie zdarzenie.Niestety nie ma możliwości oficjalnego utworzenia a
FileList
, a<input />
element wymagaFileList
w szczególności a i nie przyjmie żadnej innej wartości pozanull
. OczywiścieFileList
obiektów nie można bezpośrednio konstruować, zrobić to z jakimś starym problemem bezpieczeństwa, który najwyraźniej nie ma już znaczenia. Jedynym sposobem na złapanie jednego z zewnątrz<input />
elementu jest użycie hacka, który kopiuje i wkleja dane, aby sfałszować zdarzenie ze schowka, które może zawieraćFileList
obiekt (w zasadzie udajesz przeciągnij i upuść-plik -Twoja-witryna). Jest to możliwe w Firefoksie, ale nie w iOS Safari, więc nie było to opłacalne w moim konkretnym przypadku użycia.Przeglądarki, proszę ...
Nie trzeba dodawać, że jest to ewidentnie śmieszne. Fakt, że strony internetowe nie otrzymują żadnego powiadomienia o zmianie krytycznego elementu interfejsu użytkownika, jest po prostu śmieszny. To jest naprawdę błąd w specyfikacji, ponieważ nigdy nie był przeznaczony do pełnoekranowego interfejsu użytkownika do przechwytywania multimediów, a niewywołanie zdarzenia „zmiana” jest technicznie zgodne ze specyfikacją.
Czy jednak dostawcy przeglądarek mogą rozpoznać rzeczywistość? Można to rozwiązać za pomocą nowego zdarzenia „done”, które jest wyzwalane nawet wtedy, gdy żadna zmiana nie następuje, lub można po prostu wywołać „zmianę” i tak. Tak, byłoby to sprzeczne ze specyfikacją, ale wydedukowanie zdarzenia zmiany po stronie JavaScript jest trywialne, ale zasadniczo niemożliwe jest wymyślenie własnego zdarzenia „done”. Nawet moje rozwiązanie to tak naprawdę tylko heurystyka, o ile nie daje żadnej gwarancji na stan przeglądarki.
W obecnej postaci ten interfejs API jest zasadniczo bezużyteczny dla urządzeń mobilnych i myślę, że stosunkowo prosta zmiana przeglądarki może uczynić to nieskończenie łatwiejszym dla programistów internetowych * zejdzie z mydelniczki *.
źródło
Kiedy wybierzesz plik i klikniesz otwórz / anuluj,
input
element powinien stracić fokusblur
. Zakładając, że początkowavalue
wartośćinput
jest pusta, każda niepusta wartość w programieblur
obsługi oznaczałaby OK, a pusta wartość oznaczałaby Anulowanie.UPDATE: Nie
blur
jest wyzwalane, gdyinput
jest ukryty. Więc nie można użyć tej sztuczki z przesyłaniem opartym na IFRAME, chyba że chcesz tymczasowo wyświetlić plikinput
.źródło
blur
nie jest uruchamiany po wybraniu pliku. Nie próbowałem w innych przeglądarkach.źródło
else
oświadczenie kiedykolwiek zostanie ocenione?Większość z tych rozwiązań u mnie nie działa.
Problem polega na tym, że nigdy nie wiadomo, które zdarzenie zostanie wywołane pięścią, czy tak jest,
click
czy tak jestchange
? Nie możesz zakładać żadnej kolejności, ponieważ prawdopodobnie zależy to od implementacji przeglądarki.Przynajmniej w Operze i Chrome (koniec 2015 r.)
click
Jest uruchamiany tuż przed „wypełnieniem” danych wejściowych plikami, więc nigdy nie będziesz wiedzieć, ile czasu minie,files.length != 0
zanimclick
zostanie wywołany pochange
.Oto kod:
źródło
Po prostu posłuchaj również zdarzenia kliknięcia.
Idąc za przykładem Shiboe, oto przykład jQuery:
Możesz to zobaczyć w akcji tutaj: http://jsfiddle.net/T3Vwz
źródło
Możesz złapać anulowanie, jeśli wybierzesz ten sam plik co poprzednio i klikniesz anuluj: w tym przypadku.
Możesz to zrobić w ten sposób:
źródło
Najłatwiej jest sprawdzić, czy w pamięci tymczasowej są jakieś pliki. Jeśli chcesz uzyskać zdarzenie zmiany za każdym razem, gdy użytkownik kliknie plik wejściowy, możesz je wywołać.
źródło
Rozwiązanie Shiboe byłoby dobre, gdyby działało na mobilnym zestawie internetowym, ale tak nie jest. To, co mogę wymyślić, to dodanie detektora zdarzeń mousemove do jakiegoś obiektu dom w momencie otwarcia okna wejściowego pliku, na przykład:
Zdarzenie mousemove jest blokowane na stronie, gdy okno dialogowe pliku jest otwarte, a po jego zamknięciu sprawdza, czy w pliku wejściowym znajdują się jakieś pliki. W moim przypadku chcę, aby wskaźnik aktywności blokował rzeczy do momentu przesłania pliku, więc chcę usunąć mój wskaźnik tylko po anulowaniu.
Jednak to nie rozwiązuje problemu w przypadku urządzeń mobilnych, ponieważ nie ma myszy do poruszania. Moje rozwiązanie nie jest doskonałe, ale myślę, że jest wystarczająco dobre.
Teraz nasłuchujemy dotknięcia ekranu, aby sprawdzić te same pliki. Jestem pewien, że palec użytkownika zostanie umieszczony na ekranie dość szybko po anulowaniu i odrzuceniu tego wskaźnika aktywności.
Można również po prostu dodać wskaźnik aktywności do zdarzenia zmiany danych wejściowych pliku, ale na telefonie komórkowym często występuje kilkusekundowe opóźnienie między wyborem obrazu a uruchomieniem zdarzenia zmiany, więc jest to po prostu znacznie lepszy UX, aby wskaźnik aktywności był wyświetlany w rozpoczęcie procesu.
źródło
Znalazłem ten atrybut, jak dotąd najprostszy.
Tutaj
selectedFile
jestinput type=file
.źródło
Wiem, że to bardzo stare pytanie, ale na wszelki wypadek, gdyby komuś pomogło, stwierdziłem, używając zdarzenia onmousemove do wykrycia anulowania, że konieczne było przetestowanie dwóch lub więcej takich zdarzeń w krótkim czasie. Wynika to z faktu, że pojedyncze zdarzenia onmousemove są generowane przez przeglądarkę (Chrome 65) za każdym razem, gdy kursor jest przenoszony z okna dialogowego wyboru pliku i za każdym razem, gdy jest przenoszony z okna głównego i z powrotem. Prosty licznik zdarzeń ruchu myszy w połączeniu z krótkim limitem czasu, aby zresetować licznik z powrotem do zera, działał niewiarygodnie.
źródło
W moim przypadku musiałem ukryć przycisk przesyłania, gdy użytkownicy wybierali obrazy.
Oto, co wymyśliłem:
#image-field
to mój selektor plików. Kiedy ktoś na nią kliknie, wyłączam przycisk przesyłania formularza. Chodzi o to, że kiedy okno dialogowe pliku zostało zamknięte - nie ma znaczenia, że wybierają plik lub anulują -#image-field
wróciło fokus, więc słucham tego zdarzenia.AKTUALIZACJA
Odkryłem, że to nie działa w safari i poltergeist / phantomjs. Weź te informacje pod uwagę, jeśli chcesz je wdrożyć.
źródło
Łącząc rozwiązania Shiboe i alx, otrzymałem najbardziej niezawodny kod:
Generalnie zdarzenie mousemove załatwia sprawę, ale w przypadku, gdy użytkownik kliknął, a następnie:
... nie otrzymamy zdarzenia mousemove, dlatego nie można anulować oddzwonienia. Co więcej, jeśli użytkownik anuluje drugie okno dialogowe i wykona ruch myszą, otrzymamy 2 anulowane wywołania zwrotne. Na szczęście w obu przypadkach w dokumencie pojawia się specjalne wydarzenie focusIn jQuery, pomagając nam uniknąć takich sytuacji. Jedynym ograniczeniem jest zablokowanie zdarzenia focusIn.
źródło
mousemove
zdarzeniedocument
podczas wybierania plików w oknie dialogowym systemu operacyjnego w Chrome 56.0.2924.87 na Ubuntu 16.10. Nie ma problemu, gdy nie poruszasz myszą lub używasz tylko klawiatury do wybrania pliku. Musiałem wymienićmousemove
na,keydown
aby wykryć anulowanie tak wcześnie, jak to możliwe, ale nie „za wcześnie”, gdy okno dialogowe było nadal otwarte.Widzę, że moja odpowiedź byłaby dość nieaktualna, ale nigdy mniej. Miałem ten sam problem. Oto moje rozwiązanie. Najbardziej przydatnym wyciętym kodem był ten z KGA. Ale to nie do końca działa i jest nieco skomplikowane. Ale uprościłem to.
Ponadto głównym problemem był fakt, że wydarzenie „zmiany” nie następuje natychmiast po skupieniu, więc musimy trochę poczekać.
„#appendfile” - który użytkownik klika, aby dołączyć nowy plik. Hrefs otrzymują zdarzenia fokusu.
źródło
Możesz to wykryć tylko w ograniczonych okolicznościach. W szczególności w chrome, jeśli plik został wybrany wcześniej, a następnie kliknięto okno dialogowe pliku i kliknięto anulowanie, Chrome czyści plik i uruchamia zdarzenie onChange.
https://code.google.com/p/chromium/issues/detail?id=2508
W tym scenariuszu można to wykryć, obsługując zdarzenie onChange i sprawdzając właściwość files .
źródło
Wydaje się, że działa dla mnie (na komputerze stacjonarnym, Windows):
Używa to angularjs $ q, ale w razie potrzeby powinieneś być w stanie zastąpić go dowolnym innym frameworkiem obietnicy.
Testowane na IE11, Edge, Chrome, Firefox, ale nie wydaje się działać w Chrome na tablecie z Androidem, ponieważ nie uruchamia zdarzenia Focus.
źródło
Pole
file
typu -type, frustrujące, nie reaguje na wiele zdarzeń (rozmycie byłoby cudowne). Widzę, że wiele osób sugerujechange
rozwiązania zorientowane na orientację i są one odrzucane.change
działa, ale ma poważną wadę (w porównaniu z tym, co chcemy, aby się stało).Gdy świeżo załadujesz stronę zawierającą pole pliku, otwórz okno i naciśnij anuluj. Nic, irytująco, się nie zmienia .
To, co wybrałem, to ładowanie w stanie zamkniętym.
section#after-image
w moim przypadku jest niewidoczna. Kiedy mojefile field
zmiany, pojawia się przycisk przesyłania. Po pomyślnym przesłaniusection#after-image
zostanie wyświetlony symbol.change
zdarzenie jest wyzwalane przez to anulowanie i tam mogę (i robię) ponownie ukryć mój przycisk przesyłania, dopóki nie zostanie wybrany właściwy plik.Miałem szczęście, że ten stan z bramą był już projektem mojej formy. Nie musisz używać tego samego stylu, wystarczy, że przycisk przesyłania będzie początkowo ukryty, a po zmianie ustaw ukryte pole lub zmienną javascript na coś, co możesz monitorować po przesłaniu.
Próbowałem zmienić wartość plików [0] przed interakcją z polem. To nic nie zmieniło w przypadku wymiany.
Więc tak,
change
działa, przynajmniej tak dobre, jak zamierzamy. Pole plików jest zabezpieczone z oczywistych powodów, ale ku frustracji programistów o dobrych intencjach.To nie pasuje do mojego celu, ale możesz być w stanie
onclick
załadować ostrzeżenie (niealert()
, ponieważ powoduje to wstrzymanie przetwarzania strony) i ukryć je, jeśli zostanie wywołana zmiana, a pliki [0] są puste. Jeśli zmiana nie zostanie wyzwolona, element div pozostaje w swoim stanie.źródło
Jest na to hakerski sposób (dodaj wywołania zwrotne lub rozwiąż niektóre implementacje odroczonych / obietnic zamiast
alert()
połączeń):Jak to działa: gdy okno dialogowe wyboru pliku jest otwarte, dokument nie otrzymuje zdarzeń wskaźnika myszy. Opóźnienie 1000 ms pozwala na faktyczne pojawienie się okna dialogowego i zablokowanie okna przeglądarki. Sprawdzone w Chrome i Firefox (tylko Windows).
Ale oczywiście nie jest to niezawodny sposób wykrywania anulowanych dialogów. Chociaż może poprawić niektóre zachowanie interfejsu użytkownika.
źródło
Oto moje rozwiązanie, używając fokusa wejścia pliku (bez użycia żadnych timerów)
źródło
Error: { "message": "Uncaught SyntaxError: missing ) after argument list", "filename": "https://stacksnippets.net/js", "lineno": 51, "colno": 1 }
W najlepszym razie jest to hackerskie, ale oto działający przykład mojego rozwiązania, które wykrywa, czy użytkownik przesłał plik, i zezwala mu na kontynuację tylko wtedy, gdy przesłał plik.
Zasadniczo ukryć
Continue
,Save
,Proceed
lub niezależnie przycisk jest. Następnie w JavaScript pobierasz nazwę pliku. Jeśli nazwa pliku nie ma wartości, nie pokazujContinue
przycisku. Jeśli ma wartość, pokaż przycisk. Działa to również, jeśli najpierw prześlą plik, a następnie spróbują przesłać inny plik i klikną anuluj.Oto kod.
HTML:
JavaScript:
CSS:
W przypadku CSS wiele z tego polega na tym, aby witryna i przycisk były dostępne dla każdego. Zaprojektuj swój przycisk tak, jak lubisz.
źródło
Cóż, to nie odpowiada dokładnie na twoje pytanie. Moje założenie jest takie, że masz scenariusz, kiedy dodajesz dane wejściowe do pliku i wywołujesz wybór pliku, a jeśli użytkownik kliknie przycisk Anuluj, po prostu usuwasz dane wejściowe.
W takim przypadku: Po co dodawać puste dane wejściowe do pliku?
Utwórz go w locie, ale dodaj go do DOM tylko wtedy, gdy jest wypełniony. Na przykład:
Więc tutaj tworzę <input type = "file" /> w locie, wiążę się z jego zdarzeniem zmiany, a następnie natychmiast wywołuję kliknięcie. Zmiana będzie uruchamiana tylko wtedy, gdy użytkownik wybierze plik i kliknie OK, w przeciwnym razie dane wejściowe nie zostaną dodane do DOM, a zatem nie zostaną przesłane.
Przykład roboczy tutaj: https://jsfiddle.net/69g0Lxno/3/
źródło
// Użyj najechania zamiast rozmycia
źródło
Jeśli już potrzebujesz JQuery, to rozwiązanie może zadziałać (jest to dokładnie ten sam kod, którego faktycznie potrzebowałem w moim przypadku, chociaż użycie Promise to po prostu wymuszenie na kodzie czekania, aż wybór pliku zostanie rozwiązany):
});
źródło
W tym wątku proponowanych jest kilka rozwiązań, a ta trudność w wykryciu, kiedy użytkownik kliknie przycisk „Anuluj” w oknie wyboru pliku, jest problemem, który dotyka wiele osób.
Faktem jest, że nie ma w 100% niezawodnego sposobu na wykrycie, czy użytkownik kliknął przycisk „Anuluj” w oknie wyboru pliku. Istnieją jednak sposoby niezawodnego wykrywania, czy użytkownik dodał plik do pliku wejściowego. To jest podstawowa strategia tej odpowiedzi!
Postanowiłem dodać tę odpowiedź, ponieważ najwyraźniej inne odpowiedzi nie działają w większości przeglądarek ani nie są gwarantowane na urządzeniach mobilnych.
Krótko mówiąc, kod opiera się na 3 punktach:
Aby lepiej zrozumieć, spójrz na poniższy kod i notatki.
Dzięki! = D
źródło
Osiągnęliśmy w kątowym jak poniżej.
HTML
TS
źródło
Po prostu dodaj odbiornik „zmień” do swojego wejścia, którego typ to plik. to znaczy
Zrobiłem już przy użyciu jQuery i oczywiście każdy może używać Valina JS (zgodnie z wymaganiami).
źródło
.change()
nie jest wywoływana niezawodnie, jeśli użytkownik kliknie „Anuluj” na selektorze plików.źródło
Rozwiązanie do wyboru plików z ukrytym wejściem
Uwaga: ten kod nie wykrywa anulowania, ale oferuje sposób na obejście potrzeby wykrycia go w typowym przypadku, gdy ludzie próbują go wykryć.
Dotarłem tutaj, szukając rozwiązania do przesyłania plików za pomocą ukrytego wejścia, uważam, że jest to najczęstszy powód, aby szukać sposobu na wykrycie anulowania wejścia pliku (otwórz okno dialogowe pliku -> jeśli plik został wybrany, uruchom jakiś kod, inaczej nic nie rób), oto moje rozwiązanie:
Przykład użycia:
Zauważ, że jeśli żaden plik nie został wybrany, pierwsza linia zwróci się tylko raz, gdy
selectFile()
zostanie wywołana ponownie (lub jeśli zadzwoniłeśfileSelectorResolve()
z innego miejsca).Inny przykład:
źródło
Możesz ustawić nasłuchiwanie zmian jQuery w polu wejściowym i wykryć, że użytkownik anulował lub zamknął okno przesyłania na podstawie wartości pola.
Oto przykład:
źródło