Gambaran
Saya memiliki struktur HTML berikut dan saya telah melampirkan dragenter
dan dragleave
acara ke <div id="dropzone">
elemen.
<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>
Masalah
Ketika saya menyeret file ke atas <div id="dropzone">
, dragenter
acara tersebut diaktifkan seperti yang diharapkan. Namun, ketika saya memindahkan mouse saya ke elemen anak, seperti <div id="drag-n-drop">
, dragenter
acara dipecat untuk <div id="drag-n-drop">
elemen dan kemudian dragleave
acara dipecat untuk<div id="dropzone">
elemen.
Jika saya mengarahkan <div id="dropzone">
elemen lagi, dragenter
acara kembali dipecat, yang keren, tapi kemudian dragleave
acara dipecat untuk elemen anak yang baru saja pergi, jadiremoveClass
instruksi dijalankan, yang tidak keren.
Perilaku ini bermasalah karena 2 alasan:
Saya hanya melampirkan
dragenter
&dragleave
ke<div id="dropzone">
jadi saya tidak mengerti mengapa elemen anak-anak memiliki acara ini juga terpasang.Saya masih menyeret
<div id="dropzone">
elemen sambil melayang-layang di atas anak-anaknya jadi saya tidak ingindragleave
menembak!
jsFiddle
Berikut adalah jsFiddle untuk bermain-main dengan: http://jsfiddle.net/yYF3S/2/
Pertanyaan
Jadi ... bagaimana saya bisa membuatnya sehingga ketika saya menyeret file di atas <div id="dropzone">
elemen, dragleave
tidak memecat bahkan jika saya menyeret elemen anak-anak ... itu hanya akan menyala ketika saya meninggalkan <div id="dropzone">
elemen .. melayang-layang / menyeret di mana saja dalam batas-batas elemen tidak boleh memicu dragleave
acara.
Saya ingin ini kompatibel lintas-browser, setidaknya di browser yang mendukung HTML5 drag-n-drop, jadi jawaban ini ini tidak memadai.
Sepertinya Google dan Dropbox sudah menemukan ini, tetapi kode sumber mereka diperkecil / rumit jadi saya belum bisa mengetahuinya dari penerapannya.
e.stopPropagation();
Jawaban:
Jika Anda tidak perlu mengikat acara ke elemen turunan, Anda selalu dapat menggunakan properti pointer-events.
sumber
:hover
gaya terpisah atau klik penangan acara). Jika Anda ingin melestarikan acara-acara tersebut, berikut solusi lain yang telah saya gunakan: bensmithett.github.io/dragster.dropzone * {pointer-events: none;}
$('.element').addClass('dragging-over')
ke elemen yang Anda seret, dan$('.element').removeClass('dragging-over')
ketika Anda seret. Maka dalam CSS Anda, Anda dapat memiliki.element.dragging-over * { pointer-events: none; }
. Itu menghapus peristiwa pointer dari semua elemen anak hanya ketika Anda menyeret.Saya akhirnya menemukan solusi yang saya sukai. Saya benar-benar menemukan beberapa cara untuk melakukan apa yang saya inginkan tetapi tidak ada yang sesukses solusi saat ini ... dalam satu solusi, saya sering mengalami kerlipan sebagai akibat dari menambah / menghapus batas ke
#dropzone
elemen ... di lain, perbatasan tidak pernah dihapus jika Anda menjauh dari browser.Bagaimanapun, solusi hacky terbaik saya adalah ini:
Ini bekerja cukup baik tetapi masalah muncul di Firefox karena Firefox adalah permintaan ganda
dragenter
sehingga counter saya tidak aktif. Namun demikian, ini bukan solusi yang sangat elegan.Lalu saya menemukan pertanyaan ini: Bagaimana mendeteksi acara dragleave di Firefox ketika menyeret keluar jendela
Jadi saya mengambil jawabannya dan menerapkannya pada situasi saya:
Ini bersih dan elegan dan tampaknya berfungsi di setiap browser yang saya uji sejauh ini (belum menguji IE).
sumber
stopPropagation()
danpreventDefault()
lebih disukai. Saya akan menjatuhkanreturn false
.Ini sedikit jelek tapi berhasil, sial! ...
Pada penangan 'dragenter' Anda simpan event.target (dalam variabel di dalam penutupan Anda, atau apa pun), maka di penangan 'dragleave' Anda hanya memecat kode Anda jika event.target === yang Anda simpan.
Jika 'dragenter' Anda menembak ketika Anda tidak menginginkannya (yaitu ketika ia masuk setelah meninggalkan elemen anak), maka terakhir kali ia menyala sebelum mouse meninggalkan induk, itu pada induknya, sehingga induknya akan selalu 'dragenter' terakhir sebelum 'dragleave' yang dimaksud.
sumber
Pada awalnya, saya setuju dengan orang-orang yang mengabaikan
pointer-events: none
pendekatan itu. Tapi kemudian saya bertanya pada diri sendiri:Dalam kasus saya, saya memiliki banyak hal yang terjadi pada anak-anak, misalnya mengarahkan untuk menunjukkan tombol untuk tindakan tambahan, mengedit inline, dll ... Namun, tidak ada yang diperlukan atau bahkan bahkan diinginkan selama drag.
Dalam kasus saya, saya menggunakan sesuatu seperti ini untuk mematikan peristiwa pointer secara selektif untuk semua node anak dari wadah induk:
Gunakan pendekatan favorit Anda untuk menambah / menghapus kelas
dragging-in-progress
didragEnter
/dragLeave
event handler, seperti yang saya lakukan atau lakukan hal yang samadragStart
, et. Al.sumber
dragstart
acara tersebut dan hapus didragend
.Ini sepertinya merupakan bug Chrome.
Satu-satunya solusi yang dapat saya pikirkan adalah membuat elemen overlay transparan untuk menangkap acara Anda: http://jsfiddle.net/yYF3S/10/
JS :
HTML :
sumber
Masalahnya adalah, bahwa elemen Anda di dalam zona drop tentu saja merupakan bagian dari zona drop dan ketika Anda memasukkan anak-anak, Anda meninggalkan orang tua. Memecahkan ini tidak mudah. Anda dapat mencoba menambahkan acara ke anak-anak juga menambahkan kelas Anda lagi ke orang tua.
Acara Anda masih akan berulang kali tetapi tidak ada yang melihat.
// Edit: Gunakan acara dragmove untuk secara permanen menimpa acara dragleave:
Tetapkan acara dragleave hanya untuk dropzone.
sumber
dragleave
... ketika saya meninggalkan seorang anak, saya mungkin masih berada di dalam orangtua#dropzone
tetapi itu tidak akan memadamkandragenter
acara lagi :(dragleave
acara ini dipecat untuk elemen anak yang baru saja pergi, jadi sekali lagiremoveClass
instruksi dijalankandragleave
hanya untuk#dropzone
... jika saya bisa, saya tidak akan memiliki masalah ini.Seperti benr disebutkan dalam jawaban ini , Anda dapat mencegah node anak untuk api pada peristiwa, tetapi jika Anda perlu untuk mengikat beberapa peristiwa, lakukan ini:
Dan tambahkan yang ini ke kode JS Anda:
sumber
Jika Anda menggunakan jQuery, lihat ini: https://github.com/dancork/jquery.event.dragout
Sungguh luar biasa.
EDIT: sebenarnya, saya tidak berpikir itu tergantung pada jQuery, Anda mungkin bisa menggunakan kode bahkan tanpa itu.
sumber
dragleave
meskipun saya belum meninggalkan dropzone induk.dragout
adalah satu-satunya solusi yang bekerja untuk saya.@ hristo Saya punya solusi yang jauh lebih elegan. Periksa apakah itu sesuatu yang bisa Anda gunakan.
Usaha Anda tidak sia-sia. Saya berhasil menggunakan Anda pada awalnya, tetapi memiliki masalah berbeda di FF, Chrome. Setelah menghabiskan waktu berjam-jam, saya mendapat saran yang bekerja persis seperti yang dimaksudkan.
Begini cara implementasinya. Saya juga memanfaatkan isyarat visual untuk memandu pengguna dengan benar tentang zona penurunan.
sumber
var dropZoneHideDelay=70, dropZoneVisible=true;
dropZoneHideDelay, dropZoneVisible
diperlukan di dua'on'
acara dokumen dalam implementasi saya.Dua sen saya: Sembunyikan lapisan di atas dropzone Anda lalu perlihatkan ketika Anda menyeret, dan targetkan dragleave di atasnya.
Demo: https://jsfiddle.net/t6q4shat/
HTML
CSS
JS
sumber
Jadi bagi saya pendekatannya
pointer-events: none;
tidak bekerja dengan baik ... Jadi, inilah solusi alternatif saya:Dengan cara ini tidak mungkin untuk
dragleave
orang tua (pada anak) ataudragover
elemen anak. semoga ini membantu :)* Kelas '.active' yang saya tambahkan saat saya
dragenter
ataudragleave
. Tetapi jika Anda bekerja tanpa itu tinggalkan saja kelas.sumber
Perbaikan cepat super sederhana untuk ini, tidak diuji secara luas tetapi berfungsi di Chrome sekarang.
Maafkan Coffeescript.
Ini memperbaiki bug flicker Chrome, atau setidaknya permutasi yang menyebabkan saya bermasalah.
sumber
Jawaban ini dapat ditemukan di sini:
Dragleave HTML5 dipecat saat melayang elemen anak
sumber
Versi saya:
Dengan tata letak ini:
Aku sudah membuat dump kelas elemen untuk
e.target
,e.currentTarget
,e.relatedTarget
untuk keduadragover
dandragleave
peristiwa.Itu menunjukkan kepada saya bahwa saat meninggalkan blok induk (
.dropzone
)e.relatedTarget
bukan anak dari blok ini jadi saya tahu saya keluar dari dropzone.sumber
Di sini, salah satu solusi paling sederhana ● ︿ ●
Lihatlah biola ini <- coba seret beberapa file di dalam kotak
Anda dapat melakukan sesuatu seperti ini:
Dengan itu Anda harus sudah tahu apa yang terjadi di sini.
Lihatlah biola itu, kau tahu.
sumber
Saya memiliki masalah yang sama dan saya memperbaikinya dengan cara ini:
Masalahnya: Fungsi drop (ev) diaktifkan ketika pengguna menjatuhkan elemen di "drop zone" (elemen ul), tetapi, sayangnya, juga ketika elemen tersebut dijatuhkan di salah satu anak-anaknya (elemen li).
Cara mengatasinya:
sumber
Saya mencoba menerapkan ini sendiri untuk kotak unggah file tempat warna kotak akan berubah ketika pengguna menyeret file ke ruang kosong.
Saya menemukan solusi perpaduan yang bagus antara Javascript dan CSS. Katakanlah Anda memiliki zona droppable
div
dengan id#drop
. Tambahkan ini ke Javascript Anda:Kemudian, tambahkan ini ke CSS Anda, untuk menonaktifkan semua anak akan kelas
.inactive
:Dengan demikian, elemen anak-anak akan tidak aktif selama pengguna menyeret elemen ke atas kotak.
sumber
Saya tidak merasa puas dengan solusi yang disajikan di sini, karena saya tidak ingin kehilangan kendali atas elemen anak-anak.
Jadi saya telah menggunakan pendekatan logika yang berbeda, menerjemahkannya ke dalam plugin jQuery, yang disebut jquery-draghandler . Sama sekali tidak memanipulasi DOM, menjamin kinerja tinggi. Penggunaannya sederhana:
Ini menangani masalah dengan sempurna tanpa mengorbankan fungsi DOM.
Unduh, detail, dan penjelasan di repositori Git -nya .
sumber
frame
s dan elemen Anda berada di perbatasannya. Dalam hal ini, saya tidak menyarankan pendekatan ini.Saya sebenarnya menyukai apa yang saya lihat https://github.com/lolmaus/jquery.dragbetter/tetapi ingin berbagi alternatif yang mungkin. Strategi umum saya adalah menerapkan gaya latar belakang ke dropzone (bukan anak-anaknya) saat menyeretnya atau anak mana pun darinya (melalui menggelegak). Lalu saya menghapus gaya ketika menyeret zona penurunan. Gagasannya adalah ketika pindah ke seorang anak, bahkan jika saya menghapus gaya dari dropzone ketika meninggalkannya (dragleave menyala), saya hanya akan menerapkan kembali gaya ke dropzone induk pada menyeret setiap anak. Masalahnya tentu saja adalah bahwa ketika pindah dari dropzone ke anak dari dropzone, dragenter dipecat pada anak sebelum dragleave, jadi gaya saya diterapkan rusak. Solusi bagi saya adalah dengan menggunakan timer untuk memaksa acara dragenter kembali ke antrian pesan, memungkinkan saya untuk memprosesnya SETELAH dragleave. Saya menggunakan penutupan untuk mengakses acara di callback timer.
Ini sepertinya bekerja di chrome, yaitu, firefox dan berfungsi terlepas dari jumlah anak di dropzone. Saya sedikit gelisah tentang batas waktu yang menjamin penyeimbangan kembali peristiwa, tetapi tampaknya bekerja cukup baik untuk kasus penggunaan saya.
sumber
Saya mencoba menerapkan ini sendiri, dan saya tidak ingin Jquery atau plugin apa pun.
Saya ingin menangani unggahan file, dengan cara berikut yang dianggap terbaik bagi saya:
Struktur File:
--- / uploads {uploads directory}
--- /js/slyupload.js {file javascript.}
--- index.php
--- unggah.php
--- styles.css {hanya sedikit gaya ..}
Kode HTML:
Maka ini adalah File Javascript terlampir :: 'js / slyupload.js'
CSS:
sumber
Maaf itu javascript bukan jquery, tetapi bagi saya itu adalah cara paling logis untuk menyelesaikannya. Browser harus memanggil dropleave (elemen sebelumnya) sebelum dropenter (atau elemen baru, karena sesuatu tidak dapat memasukkan sesuatu yang lain sebelum meninggalkan hal pertama, saya tidak mengerti mengapa mereka melakukan itu! Jadi Anda hanya perlu menunda de dropleave seperti itu:
Dan dropenter akan terjadi setelah dropleave, itu saja!
sumber
Gunakan
greedy : true
untuk anak sebagai fungsi daridroppable
. Maka mulailah acara hanya diklik pada lapisan pertama.sumber