Bagaimana cara menentukan klik di luar elemen?

Saya memiliki beberapa menu HTML yang saya tampilkan secara penuh ketika pengguna mengklik judul menu-menu ini. Saya ingin menyembunyikan item-item ini ketika pengguna mengklik di luar area menu.

Apakah hal seperti ini dimungkinkan dengan jQuery?

 $("#menuscontainer").clickOutsideThisElement(function() { // Hide the menus }); 
2160
30 сент. diatur oleh Sergio del Amo 30 September. 2008-09-30 16:17 '08 pada 16:17 2008-09-30 16:17
@ 78 jawaban
  • 1
  • 2
  • 3

CATATAN Penggunaan stopEventPropagation() harus dihindari karena mengganggu aliran normal peristiwa di DOM. Lihat artikel ini untuk informasi lebih lanjut. Coba gunakan metode ini sebagai gantinya.

Lampirkan acara klik ke badan dokumen yang menutup jendela. Lampirkan acara klik terpisah ke wadah yang menghentikan distribusi di badan dokumen.

 $(window).click(function() { //Hide the menus if visible }); $('#menucontainer').click(function(event){ event.stopPropagation(); }); 
1671
30 сент. jawabannya diberikan oleh Eran Galperin 30 Sep 2008-09-30 16:38 '08 pada 16:38 2008-09-30 16:38

Anda dapat mendengarkan acara klik untuk document dan kemudian memastikan bahwa #menucontainer bukanlah leluhur atau target elemen .closest() dengan .closest() .

Jika ini bukan masalahnya, maka elemen #menucontainer berada di luar #menucontainer dan dapat disembunyikan dengan aman.

Edit - 2018-03-11

Bagi mereka yang tidak ingin menggunakan jQuery. Berikut adalah kode di atas dalam plain vanillaJS (ECMAScript6).

https://developer.mozilla.org/en-US/docs/Web/API/Element/closest. 

1212
12 июня '10 в 11:35 2010-06-12 11:35 Jawabannya diberikan Art 12 Juni '10 pada 11:35 2010-06-12 11:35

Bagaimana cara mendeteksi klik di luar elemen?

Alasan mengapa pertanyaan ini sangat populer dan memiliki banyak jawaban adalah karena itu sangat rumit. Setelah hampir delapan tahun dan lusinan jawaban, saya benar-benar terkejut melihat betapa sedikit perhatian diberikan pada aksesibilitas.

Saya ingin menyembunyikan item-item ini ketika pengguna mengklik di luar area menu.

Ini adalah tujuan mulia dan merupakan masalah aktual. Nama pertanyaannya adalah apa yang sebagian besar jawaban coba coba selesaikan, berisi ikan haring merah yang tidak bahagia.

Petunjuk: kata ini adalah "klik"!

Bahkan, Anda tidak ingin mengikat penangan klik.

Jika Anda menautkan penangan klik untuk menutup kotak dialog, Anda telah gagal. Alasan Anda gagal adalah tidak semua orang memicu peristiwa click . Pengguna yang tidak menggunakan mouse akan dapat keluar dari kotak dialog Anda (dan menu sembulan Anda mungkin jenis dialog) dengan menekan Tab , dan kemudian mereka tidak akan dapat membaca konten di balik dialog tanpa memulai click .

Jadi mari kita u>

Bagaimana cara menutup dialog ketika pengguna selesai dengan itu?

Inilah tujuannya. Sayangnya, sekarang kita harus mengikat pengguna userisfinishedwiththedialog acara userisfinishedwiththedialog , dan mengikat ini tidak begitu sederhana.

Jadi, bagaimana kita mengetahui bahwa pengguna telah selesai menggunakan dialog?

acara focusout

Awal yang baik adalah menentukan apakah fokus telah meninggalkan dialog.

Petunjuk: hati-hati dengan kejadian blur , blur tidak berlaku jika acara itu dikaitkan dengan fase menggelegak!

focusout jQuery akan sangat bagus. Jika Anda tidak bisa menggunakan jQuery, Anda bisa menggunakan blur pada fase capture:

 element.addEventListener('blur', ..., true); // use capture: ^^^^ 

Selain itu, untuk banyak dialog, Anda harus mengizinkan wadah untuk mendapatkan fokus. Tambahkan tabindex="-1" sehingga kotak dialog dapat menerima fokus secara dinamis tanpa mengganggu aliran tab.

 div { display: none; } .active { display: block; } 
Example <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor sit amet. </div> 

Jika Anda bermain dengan demo ini selama lebih dari satu menit, Anda harus segera mulai melihat masalahnya.

Pertama, tautan di kotak dialog tidak tersedia. Mencoba mengkliknya atau tab akan menutup kotak dialog sebelum interaksi terjadi. Hal ini disebabkan oleh fakta bahwa pemfokusan elemen dalam menyebabkan acara focusout sebelum focusin fokus dalam acara.

Cara mengatasinya adalah antrian status di loop acara. Ini dapat dilakukan dengan menggunakan setImmediate(...) atau setTimeout(..., 0) untuk browser yang tidak mendukung setImmediate . Setelah antri, itu dapat dibatalkan oleh focusin berikutnya:

 $('.submenu').on({ focusout: function (e) { $(this).data('submenuTimer', setTimeout(function () { $(this).removeClass('submenu--active'); }.bind(this), 0)); }, focusin: function (e) { clearTimeout($(this).data('submenuTimer')); } }); 

 div { display: none; } .active { display: block; } 
Example <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor sit amet. </div> 

Masalah kedua adalah bahwa dialog tidak akan ditutup ketika Anda mengklik kembali tautan tersebut. Ini disebabkan oleh kenyataan bahwa dialog kehi>

Seperti pada rilis sebelumnya, Anda perlu mengontrol status fokus. Menimbang bahwa perubahan status telah diantrekan, itu hanya masalah pemrosesan acara fokus dalam mode interaktif:

Seharusnya terlihat akrab.
 $('a').on({ focusout: function () { $(this.hash).data('timer', setTimeout(function () { $(this.hash).removeClass('active'); }.bind(this), 0)); }, focusin: function () { clearTimeout($(this.hash).data('timer')); } }); 

 div { display: none; } .active { display: block; } 
Example <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor sit amet. </div> 

Kunci Esc

Jika Anda berpikir bahwa semuanya dilakukan dengan mengelola status fokus, Anda dapat melakukan lebih banyak untuk menyederhanakan pengalaman pengguna.

Ini sering "menyenangkan untuk dimiliki," tetapi biasanya terjadi ketika Anda memiliki modal atau file pop-up jenis apa pun yang menutupnya dengan kunci Esc .

 keydown: function (e) { if (e.which === 27) { $(this).removeClass('active'); e.preventDefault(); } } 

 div { display: none; } .active { display: block; } 
Example <div id="example" tabindex="-1"> Lorem ipsum <a href="http://example.com">dolor sit amet. </div> 

Jika Anda tahu ada elemen khusus di kotak dialog, Anda tidak perlu >

 click: function (e) { $(this.hash) .toggleClass('submenu--active') .find('a:first') .focus(); e.preventDefault(); } 

 .menu { list-style: none; margin: 0; padding: 0; } .menu:after { clear: both; content: ''; display: table; } .menu__item { float: left; position: relative; } .menu__link { background-color: lightblue; color: black; display: block; padding: 0.5em 1em; text-decoration: none; } .menu__link:hover, .menu__link:focus { background-color: black; color: lightblue; } .submenu { border: 1px solid black; display: none; left: 0; list-style: none; margin: 0; padding: 0; position: absolute; top: 100%; } .submenu--active { display: block; } .submenu__item { width: 150px; } .submenu__link { background-color: lightblue; color: black; display: block; padding: 0.5em 1em; text-decoration: none; } .submenu__link:hover, .submenu__link:focus { background-color: black; color: lightblue; } 
Menu 1</a> <ul class="submenu" id="menu-1" tabindex="-1"> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li> </ul> </li> <li class="menu__item"> <a class="menu__link" href="#menu-2">Menu 2</a> <ul class="submenu" id="menu-2" tabindex="-1"> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li> <li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li> </ul> </li> </ul> lorem ipsum <a href="http://example.com/">dolor sit amet. 

Peran WAI-ARIA dan dukungan aksesibilitas lainnya

Saya harap jawaban ini mencakup dasar-dasar dukungan keyboard dan mouse yang tersedia untuk fungsi ini, tetapi karena ini sudah cukup signifikan, saya akan menghindari membahas peran dan atribut WAI-ARIA , tetapi saya sangat menyarankan agar pengembang merujuk pada spesifikasi untuk detailnya. peran yang harus mereka gunakan, dan atribut lain yang relevan.

220
12 июля '16 в 2:29 2016-07-12 02:29 jawabannya diberikan zzzzBov 12 Juli '16 pukul 02:29 2016-07-12 02:29

Solusi lain di sini tidak bekerja untuk saya, jadi saya harus menggunakan:

 if(!$(event.target).is('#foo')) { // hide menu } 
132
07 июля '09 в 2:10 2009-07-07 02:10 jawabannya diberikan kepada Dennis pada 07 Juli 2009 di 2:10 2009-07-07 02:10

Saya memiliki aplikasi yang bekerja mirip dengan contoh Eran, kecuali bahwa saya melampirkan acara klik ke tubuh ketika membuka menu ... Agak seperti ini:

 $('#menucontainer').click(function(event) { $('html').one('click',function() { // Hide the menus }); event.stopPropagation(); }); 

Informasi lebih lanjut tentang fungsi jQuery one()

122
30 сент. Jawaban yang diberikan oleh Joe Lencioni 30 Sep 2008-09-30 21:13 '08 pada jam 9:13 malam 2008-09-30 21:13
 $("#menuscontainer").click(function() { $(this).focus(); }); $("#menuscontainer").blur(function(){ $(this).hide(); }); 

Bekerja untuk saya baik-baik saja.

36
17 нояб. Jawabannya diberikan oleh user212621 17 November. 2009-11-17 09:13 '09 pada 9:13 2009-11-17 09:13

Sekarang ada plugin untuk ini: acara eksternal ( posting blog )

Berikut ini terjadi ketika penangan clickoutside (WLOG) terikat ke elemen:

  • sebuah elemen ditambahkan ke array yang berisi semua elemen dengan penangan clickoutside.
  • penangan klik ( namespaced ) terikat ke dokumen (jika belum ada)
  • pada setiap klik dalam dokumen, acara sisi klik dipicu untuk elemen-elemen dalam array ini yang tidak sama atau objek induk dari klik target
  • Selain itu, event.target untuk acara clickoutside diatur ke item yang diklik pengguna (sehingga Anda bahkan tahu bahwa pengguna mengklik, dan bukan hanya dia mengklik di luar).

Dengan demikian, tidak ada acara yang diakhiri karena propagasi, dan penangan klik tambahan dapat digunakan "di atas" dengan bantuan penangan eksternal.

35
05 апр. jawabannya diberikan Wolfram 05 April. 2010-04-05 13:07 '10 pada 13:07 2010-04-05 13:07

Setelah meneliti, saya menemukan tiga solusi yang berfungsi (saya lupa tautan ke halaman untuk referensi)

Keputusan pertama

 <script> //The good thing about this solution is it doesn't stop event propagation. var clickFlag = 0; $('body').on('click', function () { if(clickFlag == 0) { console.log('hide element here');  } else { clickFlag=0; } }); $('body').on('click','#testDiv', function (event) { clickFlag = 1; console.log('showed the element');  }); </script> 

Solusi kedua

 <script> $('body').on('click', function(e) { if($(e.target).closest('#testDiv').length == 0) {  } }); </script> 

Solusi ketiga

 <script> var specifiedElement = document.getElementById('testDiv'); document.addEventListener('click', function(event) { var isClickInside = specifiedElement.contains(event.target); if (isClickInside) { console.log('You clicked inside') } else { console.log('You clicked outside') } }); </script> 
32
02 нояб. jawabannya diberikan Rameez Rami 02 Nov. 2015-11-02 11:33 '15 pada 11:33 2015-11-02 11:33

Ini bekerja dengan baik untuk saya!

 $('html').click(function (e) { if (e.target.id == 'YOUR-DIV-ID') { //do something } else { //do something } }); 
29
04 июня '12 в 17:08 2012-06-04 17:08 jawabannya diberikan srinath 04 Juni '12 pada 17:08 2012-06-04 17:08

Saya tidak berpikir Anda benar-benar perlu menutup menu ketika pengguna mengkliknya; Anda perlu menutup menu ketika pengguna mengklik di mana saja pada halaman. Jika Anda mengklik menu atau menu di luar, haruskah itu menutupnya dengan benar?

Tidak menemukan jawaban yang memuaskan, saya diminta untuk menulis posting blog ini beberapa hari yang lalu. Untuk yang lebih bertele-tele, ada beberapa kesalahan yang perlu diperhatikan:

  • Jika Anda melampirkan pengendali acara klik ke elemen tubuh selama klik, pastikan untuk menunggu klik kedua sebelum menutup menu dan lepaskan acara. Jika tidak, acara klik yang membuka menu akan muncul di layar pendengar, yang harus menutup menu.
  • Jika Anda menggunakan event.stopPropogation () dalam acara klik, tidak ada elemen lain di halaman Anda yang dapat memiliki fungsi klik tempat untuk menutup.
  • Melampirkan pengendali acara klik ke elemen tubuh tidak terbatas bukanlah solusi yang efektif.
  • Membandingkan tujuan acara dan orang tuanya dengan pembuat handler mengasumsikan bahwa Anda ingin menutup menu ketika Anda mengkliknya, ketika Anda benar-benar ingin menutupnya ketika Anda mengklik di mana saja pada halaman.
  • Mendengarkan acara pada elemen tubuh akan membuat kode Anda lebih rapuh. Gaya tidak bersalah, karena dapat merusaknya: body { margin-left:auto; margin-right: auto; width:960px;} body { margin-left:auto; margin-right: auto; width:960px;}
24
19 мая '11 в 0:15 2011-05-19 00:15 jawabannya diberikan 34m0 19 Mei, '11 pada 0:15 2011-05-19 00:15

Seperti poster lain, dikatakan bahwa ada banyak kesalahan, terutama jika elemen yang Anda tampilkan (dalam hal ini, menu) memiliki elemen interaktif. Saya menemukan metode berikut ini cukup dapat diandalkan:

 $('#menuscontainer').click(function(event) { //your code that shows the menus fully //now set up an event listener so that clicking anywhere outside will close the menu $('html').click(function(event) { //check up the tree of the click target to check whether user has clicked outside of menu if ($(event.target).parents('#menuscontainer').length==0) { // your code to hide menu //this event listener has done its job so we can unbind it. $(this).unbind(event); } }) }); 
23
22 дек. balasan yang diberikan oleh benb pada 22 Desember 2011-12-22 14:59 '11 pada 14:59 2011-12-22 14:59

Solusi sederhana untuk situasi ini adalah:

 $(document).mouseup(function (e) { var container = $("YOUR SELECTOR"); // Give you class or ID if (!container.is(e.target)  // If the target of the click is not the desired div or section container.has(e.target).length === 0) // ... nor a descendant-child of the container { container.hide(); } }); 

Script di atas akan menyembunyikan div jika bagian luar acara klik div dipicu.

Untuk informasi lebih lanjut, lihat blog berikut: http://www.codecanal.com/detect-click-outside-div-using-javascript/

20
15 дек. Jawabannya diberikan oleh Jitendra Damor pada 15 Desember 2015-12-15 06:50 '15 pada 6:50 2015-12-15 06:50

Periksa titik target acara klik jendela (harus didistribusikan di jendela jika belum diambil di mana pun) dan pastikan itu bukan salah satu item menu. Jika tidak, Anda keluar dari menu.

Atau periksa posisi klik dan lihat apakah ada di area menu.

18
30 сент. Balas diberikan oleh Chris MacDonald pada 30 Sep 2008-09-30 16:20 '08 pada pukul 4:20 siang 2008-09-30 16:20

Solusi1

Alih-alih menggunakan event.stopPropagation (), yang dapat memiliki beberapa efek samping, cukup tentukan variabel flag sederhana dan tambahkan satu if kondisi. Saya mengujinya dan bekerja dengan baik tanpa efek samping dari stopPropagation:

 var flag = "1"; $('#menucontainer').click(function(event){ flag = "0"; // flag 0 means click happened in the area where we should not do any action }); $('html').click(function() { if(flag != "0"){ // Hide the menus if visible } else { flag = "1"; } }); 

Solusi2

Menggunakan kondisi if sederhana:

 $(document).on('click', function(event){ var container = $("#menucontainer"); if (!container.is(event.target)  // If the target of the click isn't the container... container.has(event.target).length === 0) // ... nor a descendant of the container { // Do whatever you want to do when click is outside the element } }); 
18
28 янв. Jawab Iman Sedighi 28 Jan 2015-01-28 20:24 '15 pada 20:24 2015-01-28 20:24

Saya sukses dengan sesuatu seperti ini:

 var $menuscontainer = ...; $('#trigger').click(function() { $menuscontainer.show(); $('body').click(function(event) { var $target = $(event.target); if ($target.parents('#menuscontainer').length == 0) { $menuscontainer.hide(); } }); }); 

Logikanya adalah sebagai berikut: ketika #menuscontainer ditampilkan, #menuscontainer penangan klik ke badan yang menyembunyikan #menuscontainer hanya jika target (klik) bukan anak-anak.

15
02 дек. Jawabannya diberikan oleh Chu Yeow 02 Des. 2010-12-02 12:53 '10 pada 12:53 2010-12-02 12:53

Sebagai pilihan:

 var $menu = $('#menucontainer'); $(document).on('click', function (e) { // If element is opened and click target is outside it, hide it if ($menu.is(':visible')  !$menu.is(e.target)  !$menu.has(e.target).length) { $menu.hide(); } }); 

Tidak ada masalah menghentikan distribusi acara dan lebih baik mempertahankan beberapa menu pada halaman yang sama, di mana mengklik menu kedua ketika Anda pertama kali membukanya akan meninggalkan penemuan pertama dalam solusi stopPropagation.

14
24 июля '14 в 12:41 2014-07-24 12:41 Jawaban diberikan oleh Bohdan Lyzanets pada 24 Juli '14 pukul 12:41 2014-07-24 12:41

Saya menemukan metode ini di beberapa plugin kalender jQuery.

 function ClickOutsideCheck(e) { var el = e.target; var popup = $('.popup:visible')[0]; if (popup==undefined) return true; while (true){ if (el == popup ) { return true; } else if (el == document) { $(".popup").hide(); return false; } else { el = $(el).parent()[0]; } } }; $(document).bind('mousedown.popup', ClickOutsideCheck); 
12
28 июля '11 в 17:06 2011-07-28 17:06 jawabannya diberikan oleh nazar kuliyev 28 Juli '11 pada 17:06 2011-07-28 17:06

Berikut adalah solusi untuk javascript vanilla untuk pemirsa di masa depan.

Saat mengklik elemen apa pun di dalam dokumen, jika pengidentifikasi elemen yang diklik diklik, atau elemen tersembunyi tidak disembunyikan, dan elemen tersembunyi tidak mengandung elemen dengan klik, alihkan elemen tersebut.

 (function () { "use strict"; var hidden = document.getElementById('hidden'); document.addEventListener('click', function (e) { if (e.target.id == 'toggle' || (hidden.style.display != 'none'  !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none'; }, false); })(); 

Jika Anda akan memiliki beberapa sakelar pada halaman yang sama, Anda dapat menggunakan sesuatu seperti ini:

  • Tambahkan nama kelas yang hidden ke elemen lipat.
  • Saat Anda mengklik dokumen, tutup semua item tersembunyi yang tidak mengandung item dengan klik dan tidak disembunyikan.
  • Jika elemen yang diklik adalah saklar, alihkan elemen yang ditentukan.

10
20 мая '15 в 1:52 2015-05-20 01:52 jawabannya diberikan kepada Tiny Giant pada 20 Mei '15 pukul 1:52 2015-05-20 01:52

Suatu peristiwa memiliki properti yang disebut event.path elemen, yang merupakan "daftar urutan statis semua leluhurnya dalam urutan pohon." Untuk memeriksa apakah suatu peristiwa telah terjadi dari elemen DOM tertentu atau salah satu elemen turunannya, cukup periksa jalur ke elemen DOM tertentu. Он также может использоваться для проверки нескольких элементов логически OR при проверке элемента в функции some .

 #main { display: inline-block; } 
var _tmr = window._tmr || (window._tmr = []);_tmr.push({id: "2334768", type: "pageView", start: (new Date()).getTime()});(function (d, w, id) {  if (d.getElementById(id)) return;  var ts = d.createElement("script"); ts.type = "text/javascript"; ts.async = true; ts.id = id;  ts.src = (d.location.protocol == "https:" ? "https:" : "http:") + "//top-fwz1.mail.ru/js/code.js";  var f = function () {var s = d.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ts, s);};  if (w.opera == "[object Opera]") { d.addEventListener("DOMContentLoaded", f, false); } else { f(); }})(document, window, "topmailru-code");