Saya memiliki beberapa menu HTML, yang saya tampilkan sepenuhnya ketika seorang pengguna mengklik bagian atas menu ini. Saya ingin menyembunyikan elemen-elemen ini ketika pengguna mengklik di luar area menu.
Apakah hal seperti ini dimungkinkan dengan jQuery?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
javascript
jquery
click
Sergio del Amo
sumber
sumber
event.target
dan tanpaevent.stopPropagation
.Jawaban:
Lampirkan acara klik ke badan dokumen yang menutup jendela. Lampirkan acara klik terpisah ke wadah yang menghentikan propagasi ke badan dokumen.
sumber
$('html').click()
bukan tubuh. Tubuh selalu memiliki tinggi isinya. Itu tidak ada banyak konten atau layar sangat tinggi, itu hanya berfungsi pada bagian yang diisi oleh tubuh.Anda dapat mendengarkan acara klik
document
dan kemudian memastikan#menucontainer
bukan leluhur atau target dari elemen yang diklik dengan menggunakan.closest()
.Jika tidak, maka elemen yang diklik berada di luar
#menucontainer
dan Anda dapat menyembunyikannya dengan aman.Edit - 2017-06-23
Anda juga dapat membersihkan setelah pendengar acara jika Anda berencana untuk mengabaikan menu dan ingin berhenti mendengarkan acara. Fungsi ini hanya akan membersihkan pendengar yang baru saja dibuat, menjaga pendengar klik lainnya aktif
document
. Dengan sintaks ES2015:Edit - 2018-03-11
Bagi mereka yang tidak ingin menggunakan jQuery. Berikut kode di atas dalam plain vanillaJS (ECMAScript6).
CATATAN: Ini didasarkan pada komentar Alex untuk hanya menggunakan
!element.contains(event.target)
bukan bagian jQuery.Tetapi
element.closest()
sekarang juga tersedia di semua browser utama (versi W3C sedikit berbeda dari yang jQuery). Polyfills dapat ditemukan di sini: Element.closest ()Edit - 2020-05-21
Jika Anda ingin pengguna dapat mengklik dan menarik di dalam elemen, lalu lepaskan mouse di luar elemen, tanpa menutup elemen:
Dan di
outsideClickListener
:sumber
!element.contains(event.target)
menggunakan Node.contains ()Alasan mengapa pertanyaan ini sangat populer dan memiliki begitu banyak jawaban adalah karena itu rumit. Setelah hampir delapan tahun dan lusinan jawaban, saya benar-benar terkejut melihat betapa sedikit perhatian diberikan pada aksesibilitas.
Ini adalah tujuan mulia dan merupakan masalah aktual . Judul pertanyaan — yang merupakan jawaban sebagian besar jawaban yang tampaknya ingin diatasi — berisi ikan haring merah yang malang.
Petunjuk: itu kata "klik" !
Anda sebenarnya tidak ingin mengikat penangan klik.
Jika Anda mengikat penangan klik untuk menutup dialog, Anda sudah gagal. Alasan Anda gagal adalah karena tidak semua orang memicu
click
acara. Pengguna yang tidak menggunakan mouse akan dapat keluar dari dialog Anda (dan menu pop-up Anda bisa dibilang jenis dialog) dengan menekan Tab, dan mereka kemudian tidak akan dapat membaca konten di balik dialog tanpa kemudian memicu suatuclick
acara.Jadi mari kita ulangi pertanyaannya.
Inilah tujuannya. Sayangnya, sekarang kita perlu mengikat
userisfinishedwiththedialog
acara, dan pengikatan itu tidak mudah.Jadi bagaimana kita bisa mendeteksi bahwa pengguna telah selesai menggunakan dialog?
focusout
peristiwaAwal yang baik adalah menentukan apakah fokus telah meninggalkan dialog.
Petunjuk: hati-hati dengan
blur
acara tersebut,blur
jangan menyebar jika acara itu terikat ke fase gelembung!jQuery
focusout
akan baik-baik saja. Jika Anda tidak dapat menggunakan jQuery, maka Anda dapat menggunakanblur
selama fase penangkapan:Juga, untuk banyak dialog Anda harus mengizinkan wadah untuk mendapatkan fokus. Tambah
tabindex="-1"
untuk memungkinkan dialog menerima fokus secara dinamis tanpa mengganggu aliran tab.Jika Anda bermain dengan demo itu selama lebih dari satu menit, Anda harus segera mulai melihat masalah.
Yang pertama adalah bahwa tautan dalam dialog tidak dapat diklik. Mencoba mengkliknya atau menabraknya akan menyebabkan dialog ditutup sebelum interaksi terjadi. Ini karena memfokuskan elemen dalam memicu suatu
focusout
peristiwa sebelum memicu suatufocusin
peristiwa lagi.Cara mengatasinya adalah mengantri perubahan status pada loop acara. Ini dapat dilakukan dengan menggunakan
setImmediate(...)
, atausetTimeout(..., 0)
untuk browser yang tidak mendukungsetImmediate
. Setelah antri itu dapat dibatalkan oleh yang berikutfocusin
:Tampilkan cuplikan kode
Masalah kedua adalah bahwa dialog tidak akan ditutup ketika tautan ditekan lagi. Ini karena dialog kehilangan fokus, memicu perilaku tutup, setelah itu klik tautan memicu dialog untuk dibuka kembali.
Mirip dengan masalah sebelumnya, kondisi fokus perlu dikelola. Mengingat bahwa perubahan status telah diantrekan, itu hanya masalah penanganan acara fokus pada pemicu dialog:
Ini seharusnya terlihat familierTampilkan cuplikan kode
Esc kunci
Jika Anda merasa sudah selesai dengan menangani status fokus, masih ada lagi yang bisa Anda lakukan untuk menyederhanakan pengalaman pengguna.
Ini sering merupakan fitur "baik untuk memiliki", tetapi itu umum bahwa ketika Anda memiliki modal atau popup dalam bentuk apa pun bahwa Esckunci akan menutupnya.
Tampilkan cuplikan kode
Jika Anda tahu Anda memiliki elemen yang bisa difokus di dalam dialog, Anda tidak perlu memfokuskan dialog secara langsung. Jika Anda membuat menu, Anda bisa memfokuskan item menu pertama.
Tampilkan cuplikan kode
Peran WAI-ARIA dan Dukungan Aksesibilitas Lainnya
Jawaban ini semoga mencakup dasar-dasar dukungan keyboard dan mouse yang dapat diakses untuk fitur ini, tetapi karena sudah cukup besar saya akan menghindari diskusi tentang peran dan atribut WAI-ARIA , namun saya sangat merekomendasikan agar pelaksana merujuk pada spesifikasi untuk perinciannya. tentang peran apa yang harus mereka gunakan dan atribut lain yang sesuai.
sumber
Solusi lain di sini tidak bekerja untuk saya, jadi saya harus menggunakan:
sumber
&& !$(event.target).parents("#foo").is("#foo")
di dalamIF
pernyataan sehingga elemen anak tidak akan menutup menu ketika diklik..is('#foo, #foo *')
, tetapi saya tidak merekomendasikan penjilidan klik yang mengikat untuk mengatasi masalah ini .!$(event.target).closest("#foo").length
akan lebih baik dan meniadakan kebutuhan untuk penambahan @ honyovk.Saya memiliki aplikasi yang bekerja mirip dengan contoh Eran, kecuali saya lampirkan acara klik ke tubuh ketika saya membuka menu ... Agak seperti ini:
Informasi lebih lanjut tentang fungsi jQuery
one()
sumber
.one
- di dalam$('html')
pawang - tulis a$('html').off('click')
.one
handler secara otomatis akan memanggiloff
(seperti yang ditampilkan dalam dokumentasi jQuery).Setelah penelitian, saya menemukan tiga solusi yang berfungsi (saya lupa tautan halaman untuk referensi)
Solusi pertama
Solusi kedua
Solusi ketiga
sumber
document.getElementsByClassName
, jika seseorang memiliki petunjuk, silakan bagikan.Bekerja untuk saya baik-baik saja.
sumber
#menucontainer
pertanyaannya adalah tentang kliktabindex="-1"
ke#menuscontainer
untuk membuatnya bekerja. Tampaknya jika Anda memasukkan tag input ke dalam wadah dan mengkliknya, wadah tersebut akan disembunyikan.Sekarang ada plugin untuk itu: acara luar ( posting blog )
Berikut ini terjadi ketika penangan klik - keluar (WLOG) terikat ke suatu elemen:
Jadi tidak ada acara yang dihentikan dari propagasi dan penangan klik tambahan dapat digunakan "di atas" elemen dengan penangan luar.
sumber
$( '#element' ).on( 'clickoutside', function( e ) { .. } );
Ini bekerja dengan baik untuk saya !!
sumber
Saya tidak berpikir apa yang sebenarnya Anda butuhkan adalah menutup menu ketika pengguna mengklik di luar; apa yang Anda butuhkan adalah untuk menutup menu ketika pengguna mengklik di mana saja pada halaman. Jika Anda mengklik pada menu, atau mematikan menu itu harus menutup kan?
Tidak menemukan jawaban yang memuaskan di atas mendorong saya untuk menulis posting blog ini beberapa hari yang lalu. Untuk yang lebih bertele-tele, ada sejumlah gotcha untuk diperhatikan:
body { margin-left:auto; margin-right: auto; width:960px;}
sumber
Seperti poster lain katakan ada banyak gotcha, terutama jika elemen yang Anda tampilkan (dalam hal ini menu) memiliki elemen interaktif. Saya menemukan metode berikut cukup kuat:
sumber
Solusi sederhana untuk situasi ini adalah:
Script di atas akan menyembunyikan
div
jika di luardiv
acara klik dipicu.Anda dapat melihat blog berikut untuk informasi lebih lanjut: http://www.codecanal.com/detect-click-outside-div-using-javascript/
sumber
Solusi1
Alih-alih menggunakan event.stopPropagation () yang dapat mempengaruhi beberapa sisi, cukup tentukan variabel flag sederhana dan tambahkan satu
if
syarat. Saya menguji ini dan bekerja dengan baik tanpa ada efek samping dari stopPropagation:Solusi2
Hanya dengan
if
kondisi sederhana :sumber
Periksa target acara klik jendela (harus merambat ke jendela, asalkan tidak ditangkap di tempat lain), dan pastikan itu bukan elemen menu. Jika tidak, maka Anda berada di luar menu Anda.
Atau periksa posisi klik, dan lihat apakah itu ada di dalam area menu.
sumber
Saya sudah sukses dengan sesuatu seperti ini:
Logikanya adalah: ketika
#menuscontainer
ditampilkan, ikat penangan klik ke badan yang menyembunyikan#menuscontainer
hanya jika target (dari klik) bukan anak dari itu.sumber
Sebagai varian:
Ini tidak memiliki masalah dengan menghentikan propagasi acara dan lebih baik mendukung beberapa menu pada halaman yang sama di mana mengklik pada menu kedua saat yang pertama terbuka akan meninggalkan yang pertama terbuka dalam solusi stopPropagation.
sumber
Acara ini memiliki properti yang disebut event.path dari elemen yang merupakan "daftar urutan statis semua leluhurnya dalam urutan pohon" . Untuk memeriksa apakah suatu peristiwa berasal dari elemen DOM tertentu atau salah satu dari anak-anaknya, cukup periksa lintasan untuk elemen DOM tertentu. Itu juga dapat digunakan untuk memeriksa beberapa elemen dengan secara logis
OR
memeriksa elemen padasome
fungsi.Jadi untuk kasus Anda Seharusnya begitu
sumber
event.path
bukanlah suatu hal.Saya menemukan metode ini di beberapa plugin kalender jQuery.
sumber
Ini adalah solusi JavaScript vanili untuk pemirsa di masa depan.
Setelah mengklik elemen apa pun di dalam dokumen, jika id elemen yang diklik diaktifkan, atau elemen tersembunyi tidak disembunyikan dan elemen tersembunyi tidak mengandung elemen yang diklik, alihkan elemen tersebut.
Tampilkan cuplikan kode
Jika Anda akan memiliki beberapa matikan di halaman yang sama, Anda dapat menggunakan sesuatu seperti ini:
hidden
ke item yang dapat dilipat.sumber
Saya terkejut tidak ada yang benar-benar mengakui
focusout
acara:sumber
Jika Anda membuat skrip untuk IE dan FF 3. * dan Anda hanya ingin tahu apakah klik itu terjadi dalam area kotak tertentu, Anda juga bisa menggunakan sesuatu seperti:
sumber
Alih-alih menggunakan gangguan aliran, kejadian blur / fokus, atau teknik rumit lainnya, cukup sesuaikan aliran acara dengan kekerabatan elemen:
Untuk menghapus klik di luar pendengar acara, cukup:
sumber
#menuscontainer
Anda masih melalui orang tua itu. Anda harus terlebih dahulu memeriksa itu, dan jika itu bukan elemen itu, maka naik pohon DOM.if(!($(event.target).is("#menuscontainer") || $(event.target).parents().is("#menuscontainer"))){
. Ini adalah pengoptimalan kecil, tetapi hanya terjadi beberapa kali dalam masa program Anda: untuk setiap klik, jikaclick.menu-outside
acara tersebut terdaftar. Lebih panjang (+32 karakter) dan tidak menggunakan metode chainingMenggunakan:
sumber
Jika seseorang yang penasaran di sini adalah solusi javascript (es6):
dan es5, untuk berjaga-jaga:
});
sumber
Berikut ini adalah solusi sederhana dengan javascript murni. Ini terkini dengan ES6 :
sumber
() => {}
alih - alihfunction() {}
. Apa yang Anda miliki di sana diklasifikasikan sebagai JavaScript biasa dengan sentuhan ES6.Kaitkan pendengar acara klik pada dokumen. Di dalam pendengar acara, Anda dapat melihat objek acara , khususnya, event.target untuk melihat elemen apa yang diklik:
sumber
Saya telah menggunakan skrip di bawah ini dan selesai dengan jQuery.
Di bawah ini temukan kode HTML
Anda dapat membaca tutorialnya di sini
sumber
Jika Anda mengklik dokumen tersebut, sembunyikan elemen yang diberikan, kecuali jika Anda mengklik elemen yang sama.
sumber
Suara positif untuk jawaban paling populer, tetapi tambahkan
jadi, klik pada bilah gulir tidak [menyembunyikan atau apa pun] elemen target Anda.
sumber
Untuk penggunaan yang lebih mudah, dan kode yang lebih ekspresif, saya membuat plugin jQuery untuk ini:
Catatan: target adalah elemen yang sebenarnya diklik pengguna. Tetapi panggilan balik masih dieksekusi dalam konteks elemen asli, sehingga Anda dapat memanfaatkan ini seperti yang Anda harapkan dalam panggilan balik jQuery.
Plugin:
Secara default, pendengar peristiwa klik ditempatkan pada dokumen. Namun, jika Anda ingin membatasi ruang lingkup pendengar acara, Anda bisa meneruskan dalam objek jQuery yang mewakili elemen tingkat induk yang akan menjadi induk teratas di mana klik akan didengarkan. Ini mencegah pendengar acara tingkat dokumen yang tidak perlu. Jelas, itu tidak akan berfungsi kecuali elemen induk yang disediakan adalah induk dari elemen awal Anda.
Gunakan seperti ini:
sumber