Bagaimana saya bisa mendeteksi ketika pengguna membatalkan input file menggunakan input file html?
onChange memungkinkan saya mendeteksi kapan mereka memilih file, tetapi saya juga ingin tahu kapan mereka membatalkan (tutup dialog pilih file tanpa memilih apa pun).
e.target.files
Jawaban:
Meskipun bukan solusi langsung, dan juga buruk karena hanya (sejauh yang saya uji) berfungsi dengan onfocus (memerlukan pemblokiran acara yang cukup membatasi) Anda dapat mencapainya dengan yang berikut:
Yang menyenangkan tentang ini, adalah Anda dapat melampirkan / melepaskannya tepat waktu dengan acara file, dan tampaknya juga berfungsi dengan baik dengan input tersembunyi (keuntungan yang pasti jika Anda menggunakan solusi visual untuk tipe input default jelek = ' mengajukan'). Setelah itu, Anda hanya perlu mencari tahu apakah nilai masukannya berubah.
Sebuah contoh:
Lihat aksinya: http://jsfiddle.net/Shiboe/yuK3r/6/
Sayangnya, ini sepertinya hanya berfungsi di browser webkit. Mungkin orang lain dapat mengetahui solusi firefox / IE
sumber
addEventListener("focus",fn,{once: true})
. Namun saya tidak bisa membuatnya menyala sama sekali menggunakandocument.body.addEventListener
.. Saya tidak tahu mengapa. Sebaliknya saya mendapat hasil yang sama denganwindow.addEventListener
.mousemove
acara padawindow.document
selain untuk mendengarkanfocus
padawindow
tampaknya bekerja di mana-mana (setidaknya di browser modern, saya tidak peduli tentang kecelakaan lalu-dekade). Pada dasarnya, setiap peristiwa interaksi dapat digunakan untuk tugas ini yang diblokir oleh dialog buka file yang terbuka.Tidak boleh.
Hasil dari dialog file tidak diekspos ke browser.
sumber
change
peristiwa yang dikirim.change
acara yang dikirim untuk itu juga.Jadi saya akan melemparkan topi saya ke pertanyaan ini karena saya menemukan solusi baru. Saya memiliki Aplikasi Web Progresif yang memungkinkan pengguna untuk mengambil foto dan video dan mengunggahnya. Kami menggunakan WebRTC bila memungkinkan, tetapi kembali ke pemilih file HTML5 untuk perangkat dengan dukungan yang lebih sedikit * batuk Safari batuk *.Jika Anda bekerja secara khusus pada aplikasi web seluler Android / iOS yang menggunakan kamera asli untuk mengambil foto / video secara langsung, maka ini adalah solusi terbaik yang saya temukan.
Inti dari masalah ini adalah ketika halaman dimuat,
file
isnull
, tetapi kemudian ketika pengguna membuka dialog dan menekan "Batal",file
itu diamnull
, maka itu tidak "berubah", jadi tidak ada peristiwa "perubahan" yang dipicu. Untuk desktop, ini tidak terlalu buruk karena sebagian besar UI desktop tidak bergantung pada mengetahui kapan pembatalan dipanggil, tetapi UI seluler yang memunculkan kamera untuk mengambil foto / video sangat bergantung pada mengetahui kapan pembatalan ditekan.Saya awalnya menggunakan
document.body.onfocus
acara tersebut untuk mendeteksi ketika pengguna kembali dari pemilih file, dan ini berfungsi untuk sebagian besar perangkat, tetapi iOS 11.3 merusaknya karena acara itu tidak dipicu.Konsep
Solusi saya untuk ini adalah * ngeri * untuk mengukur waktu CPU untuk menentukan apakah halaman saat ini berada di latar depan atau latar belakang. Di perangkat seluler, waktu pemrosesan diberikan ke aplikasi yang saat ini berada di latar depan. Saat kamera terlihat, itu akan mencuri waktu CPU dan menurunkan prioritas browser. Yang perlu kita lakukan adalah mengukur berapa banyak waktu pemrosesan yang diberikan halaman kita, ketika kamera diluncurkan, waktu yang tersedia akan turun secara drastis. Saat kamera ditutup (baik dibatalkan atau tidak), waktu yang tersedia melonjak kembali.
Penerapan
Kita dapat mengukur waktu CPU dengan menggunakan
setTimeout()
untuk memanggil callback dalam X milidetik, lalu mengukur berapa lama waktu yang dibutuhkan untuk benar-benar memanggilnya. Browser tidak akan pernah memanggilnya tepat setelah X milidetik, tetapi jika ditutup secara wajar maka kita harus berada di latar depan. Jika browser sangat jauh (lebih dari 10x lebih lambat dari yang diminta) maka kita harus berada di latar belakang. Implementasi dasar dari ini seperti:Saya menguji ini pada versi terbaru iOS dan Android, memunculkan kamera asli dengan mengatur atribut pada
<input />
elemen.Ini berhasil sebenarnya jauh lebih baik dari yang saya harapkan. Ini menjalankan 10 percobaan dengan meminta timer untuk dipanggil dalam 25 milidetik. Kemudian mengukur berapa lama waktu yang dibutuhkan untuk memanggil, dan jika rata-rata 10 uji coba kurang dari 50 milidetik, kami berasumsi bahwa kami harus berada di latar depan dan kamera hilang. Jika lebih dari 50 milidetik, maka kita harus tetap berada di latar belakang dan harus terus menunggu.
Beberapa detail tambahan
Saya menggunakan
setTimeout()
daripadasetInterval()
karena yang terakhir dapat mengantri beberapa pemanggilan yang dieksekusi segera setelah satu sama lain. Hal ini secara drastis dapat meningkatkan gangguan dalam data kami, jadi saya tetap menggunakannyasetTimeout()
meskipun sedikit lebih rumit untuk melakukannya.Angka-angka tertentu ini bekerja dengan baik untuk saya, meskipun saya telah melihat setidaknya satu kali contoh di mana penutupan kamera terdeteksi sebelum waktunya. Saya yakin ini karena kamera mungkin lambat untuk dibuka, dan perangkat dapat menjalankan 10 uji coba sebelum benar-benar menjadi latar belakang. Menambahkan lebih banyak uji coba atau menunggu sekitar 25-50 milidetik sebelum memulai fungsi ini mungkin bisa menjadi solusi untuk itu.
Desktop
Sayangnya, ini tidak benar-benar berfungsi untuk browser desktop. Secara teori, trik yang sama dimungkinkan karena mereka memprioritaskan halaman saat ini daripada halaman latar belakang. Namun banyak desktop memiliki sumber daya yang cukup untuk menjaga halaman tetap berjalan dengan kecepatan penuh bahkan saat di-background, jadi strategi ini tidak benar-benar berfungsi dalam praktiknya.
Solusi alternatif
Salah satu solusi alternatif yang tidak banyak disebutkan orang yang saya eksplorasi adalah mengejek a
FileList
. Kita mulai dengannull
di<input />
dan kemudian jika pengguna membuka kamera dan membatalkan mereka kembalinull
, yang bukan merupakan perubahan dan tidak ada peristiwa yang akan dipicu. Salah satu solusinya adalah menetapkan file dummy ke<input />
awal halaman, oleh karena itu menyetel kenull
akan menjadi perubahan yang akan memicu peristiwa yang sesuai.Sayangnya, tidak ada cara resmi untuk membuat a
FileList
, dan<input />
elemen tersebut memerlukanFileList
khususnya dan tidak akan menerima nilai lain selain itunull
. Secara alami,FileList
objek tidak dapat dibangun secara langsung, lakukan untuk beberapa masalah keamanan lama yang tampaknya tidak relevan lagi. Satu-satunya cara untuk mendapatkan salah satu di luar<input />
elemen adalah dengan memanfaatkan peretasan yang menyalin-tempel data untuk memalsukan acara clipboard yang dapat berisiFileList
objek (Anda pada dasarnya memalsukan drag-and-drop-a-file-on acara situs web Anda). Ini dimungkinkan di Firefox, tetapi tidak untuk iOS Safari, jadi tidak layak untuk kasus penggunaan khusus saya.Peramban, mohon ...
Tak perlu dikatakan, ini benar-benar konyol. Fakta bahwa halaman web tidak diberi pemberitahuan bahwa elemen UI kritis telah berubah sungguh menggelikan. Ini benar-benar bug dalam spesifikasi, karena tidak pernah dimaksudkan untuk UI tangkapan media layar penuh, dan tidak memicu peristiwa "ubah" secara teknis ke spesifikasi.
Namun , dapatkah vendor browser mengenali kenyataan ini? Ini dapat diselesaikan dengan peristiwa "selesai" baru yang dipicu bahkan ketika tidak ada perubahan yang terjadi, atau Anda bisa saja memicu "perubahan". Ya, itu akan bertentangan dengan spesifikasi, tapi itu sepele bagi saya untuk menghapus peristiwa perubahan di sisi JavaScript, namun pada dasarnya tidak mungkin untuk menciptakan acara "selesai" saya sendiri. Bahkan solusi saya benar-benar hanya heuristik, jika tidak ada jaminan tentang status browser.
Seperti berdiri, API ini pada dasarnya tidak dapat digunakan untuk perangkat seluler, dan menurut saya perubahan browser yang relatif sederhana dapat membuat ini jauh lebih mudah bagi pengembang web * keluar dari kotak sabun *.
sumber
Saat Anda memilih file dan mengklik buka / batal,
input
elemen akan kehilangan fokus aliasblur
. Dengan asumsi awalvalue
dariinput
kosong, setiap nilai yang kosong di Andablur
handler akan mengindikasikan OK, dan nilai kosong berarti Batal.UPDATE: Tidak
blur
dipicu saatinput
tersembunyi. Jadi tidak dapat menggunakan trik ini dengan unggahan berbasis IFRAME, kecuali Anda ingin menampilkan fileinput
.sumber
blur
tidak dipicu saat Anda memilih file. Belum mencoba di browser lain.sumber
else
pernyataan Anda pernah dievaluasi?Sebagian besar solusi ini tidak berhasil untuk saya.
Masalahnya adalah Anda tidak pernah tahu peristiwa mana yang akan memicu tinju, apakah itu
click
atau apakah ituchange
? Anda tidak dapat mengasumsikan urutan apa pun, karena mungkin tergantung pada implementasi browser.Setidaknya di Opera dan Chrome (akhir 2015)
click
dipicu tepat sebelum 'mengisi' input dengan file, jadi Anda tidak akan pernah tahu berapa lamafiles.length != 0
sampai Anda menundaclick
untuk dipicu setelahnyachange
.Ini kodenya:
sumber
Dengarkan acara klik juga.
Mengikuti dari contoh Shiboe, berikut adalah contoh jQuery:
Anda dapat melihatnya beraksi di sini: http://jsfiddle.net/T3Vwz
sumber
Anda dapat menangkap pembatalan jika Anda memilih file yang sama seperti sebelumnya dan Anda mengklik batal: dalam kasus ini.
Anda bisa melakukannya seperti ini:
sumber
Cara termudah adalah dengan memeriksa apakah ada file di memori sementara. Jika Anda ingin mendapatkan peristiwa perubahan setiap kali pengguna mengklik input file, Anda dapat memicunya.
sumber
Solusi Shiboe akan bagus jika berfungsi di webkit seluler, tetapi tidak. Yang bisa saya dapatkan adalah menambahkan pendengar acara mousemove ke beberapa objek dom pada saat jendela input file dibuka, seperti:
Peristiwa mousemove diblokir dari halaman saat dialog file terbuka, dan ketika ditutup, pemeriksaan untuk melihat apakah ada file dalam input file. Dalam kasus saya, saya ingin indikator aktivitas memblokir hal-hal sampai file diunggah, jadi saya hanya ingin menghapus indikator saya saat membatalkan.
Namun ini tidak menyelesaikan untuk seluler, karena tidak ada mouse untuk bergerak. Solusi saya di sana kurang sempurna, tapi menurut saya cukup bagus.
Sekarang kami mendengarkan sentuhan di layar untuk melakukan pemeriksaan file yang sama. Saya cukup yakin bahwa jari pengguna akan diletakkan di layar dengan cukup cepat setelah membatalkan dan menutup indikator aktivitas ini.
Anda juga bisa menambahkan indikator aktivitas pada acara perubahan input file, tetapi pada perangkat seluler sering kali ada jeda beberapa detik antara memilih gambar dan pengaktifan acara perubahan, jadi UX yang jauh lebih baik untuk indikator aktivitas yang akan ditampilkan di memulai proses.
sumber
Saya menemukan atribut ini, yang paling sederhana.
Ini,
selectedFile
adalahinput type=file
.sumber
Saya tahu ini adalah pertanyaan yang sangat lama tetapi untuk berjaga-jaga jika itu membantu seseorang, saya menemukan saat menggunakan acara onmousemove untuk mendeteksi pembatalan, bahwa perlu untuk menguji dua atau lebih acara semacam itu dalam waktu singkat. Ini karena peristiwa pemindahan tunggal satu kali dihasilkan oleh browser (Chrome 65) setiap kali kursor dipindahkan keluar dari jendela dialog file yang dipilih dan setiap kali dipindahkan dari jendela utama dan masuk kembali. Penghitung sederhana peristiwa gerakan mouse ditambah dengan batas waktu durasi singkat untuk mengatur ulang penghitung kembali ke nol bekerja dengan baik.
sumber
Dalam kasus saya, saya harus menyembunyikan tombol kirim saat pengguna memilih gambar.
Inilah yang saya dapatkan:
#image-field
adalah pemilih file saya. Ketika seseorang mengkliknya, saya menonaktifkan tombol pengiriman formulir. Intinya adalah, ketika dialog file ditutup - tidak masalah mereka memilih file atau membatalkan -#image-field
mendapatkan fokus kembali, jadi saya mendengarkan acara itu.MEMPERBARUI
Saya menemukan bahwa, ini tidak berfungsi di safari dan poltergeist / phantomjs. Pertimbangkan info ini jika Anda ingin menerapkannya.
sumber
Menggabungkan solusi Shiboe dan alx, saya mendapatkan kode yang paling andal:
Umumnya, acara mousemove melakukan trik, tetapi jika pengguna melakukan klik dan dari:
... kami tidak akan mendapatkan acara mousemove maka tidak ada panggilan balik pembatalan. Selain itu, jika pengguna membatalkan dialog kedua dan membuat mouse bergerak, kita akan mendapatkan 2 panggilan balik pembatalan. Untungnya, peristiwa jQuery focusIn khusus menggelembung ke dokumen dalam kedua kasus, membantu kita menghindari situasi seperti itu. Satu-satunya batasan adalah jika seseorang memblokir acara focusIn.
sumber
mousemove
acara tersebutdocument
saat memilih file dalam dialog OS di Chrome 56.0.2924.87 di Ubuntu 16.10. Tidak masalah, saat tidak menggerakkan mouse, atau hanya menggunakan keyboard untuk memilih file. Saya harus menggantimousemove
bykeydown
untuk mendeteksi pembatalan sedini mungkin, tetapi tidak "terlalu dini", saat dialog masih terbuka.Saya melihat bahwa tanggapan saya akan sangat ketinggalan zaman, tetapi tidak pernah berkurang. Saya menghadapi masalah yang sama. Jadi inilah solusi saya. Potongan kode yang paling berguna adalah kode KGA. Tapi itu tidak sepenuhnya berfungsi dan agak rumit. Tapi saya menyederhanakannya.
Selain itu, pembuat masalah utama adalah fakta bahwa peristiwa 'perubahan' tidak datang langsung setelah fokus, jadi kita harus menunggu beberapa saat.
"#appendfile" - yang diklik pengguna untuk menambahkan file baru. Hrefs mendapatkan acara fokus.
sumber
Anda hanya dapat mendeteksi ini dalam keadaan terbatas. Secara khusus, di chrome jika file dipilih sebelumnya dan kemudian dialog file diklik dan batal diklik, Chrome menghapus file dan mengaktifkan peristiwa onChange.
https://code.google.com/p/chromium/issues/detail?id=2508
Dalam skenario ini, Anda dapat mendeteksi ini dengan menangani peristiwa onChange dan memeriksa properti file .
sumber
Hal berikut tampaknya berhasil untuk saya (di desktop, windows):
Ini memang menggunakan angularjs $ q tetapi Anda harus dapat menggantinya dengan framework promise lainnya jika diperlukan.
Diuji di IE11, Edge, Chrome, Firefox, tetapi tampaknya tidak berfungsi di Chrome pada Tablet Android karena tidak mengaktifkan acara Focus.
sumber
Bidang
file
-type, dengan frustrasi, tidak merespons banyak peristiwa (blur akan menyenangkan). Saya melihat banyak orang menyarankanchange
solusi berorientasi dan mereka mendapatkan suara negatif.change
berhasil, tetapi memiliki kelemahan utama (vs apa yang kita inginkan terjadi).Saat Anda baru memuat halaman yang berisi bidang file, buka kotak dan tekan batal. Tidak ada, yang membuat frustrasi, berubah .
Apa yang saya pilih untuk dilakukan adalah memuat dalam keadaan terjaga keamanannya.
section#after-image
dalam kasus saya tersembunyi dari pandangan. Saat sayafile field
berubah, tombol unggah ditampilkan. Setelah unggahan berhasil,section#after-image
ditampilkan.change
peristiwa tersebut dipicu oleh pembatalan ini, dan di sana saya dapat (dan melakukan) menyembunyikan kembali tombol unggah saya hingga file yang sesuai dipilih.Saya beruntung karena kondisi gerbang ini sudah menjadi desain bentuk saya. Anda tidak perlu menggunakan gaya yang sama, cukup dengan menyembunyikan tombol unggah dan setelah diubah, menyetel bidang tersembunyi atau variabel javascript ke sesuatu yang dapat Anda pantau saat dikirim.
Saya mencoba mengubah nilai file [0] sebelum bidang itu berinteraksi. Ini tidak melakukan apa-apa tentang onchange.
Jadi ya,
change
berhasil, setidaknya sebaik yang akan kita dapatkan. Filefield diamankan, untuk alasan yang jelas, tetapi membuat frustrasi pengembang yang bermaksud baik.Ini tidak sesuai dengan tujuan saya, tetapi Anda mungkin bisa
onclick
,, memuat prompt peringatan (bukanalert()
, karena itu menghambat pemrosesan halaman), dan menyembunyikannya jika perubahan dipicu dan file [0] bernilai null. Jika perubahan tidak dipicu, div tetap dalam statusnya.sumber
Ada cara hackish untuk melakukan ini (menambahkan callback atau menyelesaikan beberapa implementasi yang ditangguhkan / janji alih-alih
alert()
panggilan):Cara kerjanya: saat dialog pemilihan file terbuka, dokumen tidak menerima peristiwa penunjuk mouse. Ada penundaan 1000ms untuk memungkinkan dialog benar-benar muncul dan memblokir jendela browser. Dicentang di Chrome dan Firefox (khusus Windows).
Tapi ini bukan cara yang dapat diandalkan untuk mendeteksi dialog yang dibatalkan, tentunya. Padahal, mungkin meningkatkan beberapa perilaku UI untuk Anda.
sumber
Inilah solusi saya, menggunakan fokus input file (tidak menggunakan timer apa pun)
sumber
Error: { "message": "Uncaught SyntaxError: missing ) after argument list", "filename": "https://stacksnippets.net/js", "lineno": 51, "colno": 1 }
Ini paling tidak hacky, tetapi berikut adalah contoh yang berfungsi dari solusi saya untuk mendeteksi apakah pengguna telah mengunggah file atau tidak, dan hanya mengizinkan mereka untuk melanjutkan jika mereka telah mengunggah file.
Pada dasarnya menyembunyikan
Continue
,Save
,Proceed
atau apa pun tombol Anda. Kemudian di JavaScript Anda mengambil nama file. Jika nama file tidak memiliki nilai, maka jangan tampilkanContinue
tombolnya. Jika memang memiliki nilai, maka tunjukkan tombolnya. Ini juga berfungsi jika mereka pada awalnya mengunggah file dan kemudian mereka mencoba mengunggah file yang berbeda dan mengeklik batal.Ini kodenya.
HTML:
JavaScript:
CSS:
Untuk CSS, banyak hal ini untuk membuat situs web dan tombol dapat diakses oleh semua orang. Atur gaya tombol Anda sesuai keinginan.
sumber
Nah, ini tidak benar-benar menjawab pertanyaan Anda. Asumsi saya adalah, Anda memiliki skenario, ketika Anda menambahkan input file, dan menjalankan pemilihan file, dan jika pengguna menekan batal, Anda cukup menghapus input tersebut.
Jika demikian, maka: Mengapa menambahkan input file kosong?
Buat satu dengan cepat, tetapi tambahkan ke DOM hanya jika sudah diisi. Seperti ini:
Jadi di sini saya membuat <input type = "file" /> dengan cepat, mengikat ke acara perubahannya dan kemudian segera memanggil klik. On change akan aktif hanya ketika pengguna memilih file dan menekan Ok, jika tidak, input tidak akan ditambahkan ke DOM, oleh karena itu tidak akan dikirimkan.
Contoh kerja di sini: https://jsfiddle.net/69g0Lxno/3/
sumber
// Gunakan hover, bukan blur
sumber
Jika Anda sudah memerlukan JQuery, solusi ini mungkin berhasil (ini adalah kode yang sama persis yang saya butuhkan dalam kasus saya, meskipun menggunakan Promise hanya untuk memaksa kode menunggu hingga pemilihan file diselesaikan):
});
sumber
Ada beberapa solusi yang diusulkan di utas ini dan kesulitan untuk mendeteksi saat pengguna mengklik tombol "Batal" pada kotak pemilihan file merupakan masalah yang mempengaruhi banyak orang.
Faktanya adalah bahwa tidak ada cara yang 100% dapat diandalkan untuk mendeteksi jika pengguna telah mengklik tombol "Batal" pada kotak pemilihan file. Tetapi ada cara untuk mendeteksi dengan andal jika pengguna telah menambahkan file ke file input. Jadi inilah strategi dasar dari jawaban ini!
Saya memutuskan untuk menambahkan jawaban ini karena ternyata jawaban lain tidak berfungsi di sebagian besar browser atau dijamin di perangkat seluler.
Secara singkat kode ini didasarkan pada 3 poin:
Untuk pemahaman yang lebih baik, lihat kode di bawah ini dan juga catatannya.
Terima kasih! = D
sumber
Kami mencapai sudut seperti di bawah ini.
HTML
TS
sumber
Cukup tambahkan pendengar 'ubah' pada masukan Anda yang tipenya adalah file. yaitu
Saya telah selesai menggunakan jQuery dan jelas siapa pun dapat menggunakan valina JS (sesuai kebutuhan).
sumber
.change()
tidak dapat dipanggil secara andal jika pengguna mengklik "batal" pada alat pilih file.sumber
Solusi untuk pemilihan file dengan input tersembunyi
Catatan: kode ini tidak mendeteksi pembatalan, ia menawarkan cara untuk menghindari kebutuhan untuk mendeteksinya dalam kasus umum di mana orang mencoba mendeteksinya.
Saya sampai di sini sambil mencari solusi untuk mengunggah file menggunakan input tersembunyi, saya percaya bahwa ini adalah alasan paling umum untuk mencari cara untuk mendeteksi pembatalan input file (buka dialog file -> jika file dipilih kemudian jalankan beberapa kode, jika tidak lakukan apa-apa), inilah solusi saya:
Contoh penggunaan:
Perhatikan bahwa jika tidak ada file yang dipilih maka baris pertama akan kembali hanya sekali
selectFile()
dipanggil lagi (atau jika Anda meneleponfileSelectorResolve()
dari tempat lain).Contoh lain:
sumber
Anda dapat membuat pemroses perubahan jquery di kolom input dan mendeteksi pengguna tersebut membatalkan atau menutup jendela upload dengan nilai kolom tersebut.
berikut ini contohnya:
sumber