Kaip nustatyti paspaudimą už elemento

Turiu kai kuriuos HTML meniu, kuriuos visiškai rodau, kai vartotojas spusteli šių meniu pavadinimą. Norėčiau paslėpti šiuos elementus, kai vartotojas spusteli už meniu srities.

Ar kažkas panašaus į jQuery?

 $("#menuscontainer").clickOutsideThisElement(function() { // Hide the menus }); 
2160
30 сент. nustatytas Sergio del Amo 30 sep. 2008-09-30 16:17 '08 at 4:17 pm 2008-09-30 16:17
@ 78 atsakymai
  • 1
  • 2
  • 3

PASTABA. Reikia vengti stopEventPropagation() naudojimo, nes tai trukdo normaliam įvykių srautui DOM. Daugiau informacijos rasite šiame straipsnyje . Pabandykite naudoti šį metodą .

Pridėkite paspaudimo įvykį prie dokumento, uždarančio >

 $(window).click(function() { //Hide the menus if visible }); $('#menucontainer').click(function(event){ event.stopPropagation(); }); 
1671 m
30 сент. atsakymą pateikė Eran Galperin 30 rugsėjis 2008-09-30 16:38 '08 at 4:38 pm 2008-09-30 16:38

Galite klausytis document paspaudimo įvykio ir tada įsitikinti, kad #menucontainer nėra .closest() elemento protėvis ar tikslas .closest() .

Jei taip nėra, #menucontainer elementas yra už #menucontainer ir gali būti saugiai paslėptas.

 export function hideOnClickOutside(selector) { const outsideClickListener = (event) => { $target = $(event.target); if (!$target.closest(selector).length  $(selector).is(':visible')) { $(selector).hide(); removeClickListener(); } } const removeClickListener = () => { document.removeEventListener('click', outsideClickListener) } document.addEventListener('click', outsideClickListener) } 
border=0

Redaguoti - 2018-03-11

Tiems, kurie nenori naudoti jQuery. Čia yra aukščiau pateiktas kodas paprastame vanillaJS (ECMAScript6).

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

1212
12 июня '10 в 11:35 2010-06-12 11:35 Atsakymas duotas Art 12 birželio 10 d. 11:35 2010-06-12 11:35

Kaip nustatyti paspaudimą už elemento?

Priežastis, dėl kurios šis klausimas yra toks populiarus ir turi tiek daug atsakymų, yra tai, kad jis yra apgaulingai sudėtingas. Po beveik aštuonerių metų ir dešimčių atsakymų aš tikrai nustebau matydamas, kaip mažai dėmesio skiriama prieinamumui.

Norėčiau paslėpti šiuos elementus, kai vartotojas spusteli už meniu srities.

Tai kilminga priežastis ir yra tikra problema. Klausimo pavadinimas yra tai, ką dauguma atsakymų, atrodo, bando išspręsti, yra nelaimingas raudonas silkė.

Patarimas: šis žodis yra „spustelėkite“!

Iš tikrųjų nenorite susieti paspaudimų tvarkytojų.

Jei uždarote dialogo >click įvykius. Vartotojai, nenaudojantys pelės, galės išeiti iš dialogo >Tab“ , ir tada jie negalės perskaityti turinio už dialogo, nepradėdami click .

Taigi, pakeiskime klausimą.

Kaip uždaryti dialogą, kai naudotojas jį baigia?

Tai yra tikslas. Deja, dabar privalome susieti userisfinishedwiththedialog , ir šis įpareigojimas nėra toks paprastas.

Taigi, kaip galime sužinoti, kad vartotojas baigė naudoti dialogą?

focusout renginys

Gera pradžia - nustatyti, ar dėmesys buvo paliktas dialogui.

Patarimas: būkite atsargūs, jei įvykis blur , blur netaikomas, jei įvykis buvo susijęs su burbuliavimo etapu!

jQuery focusout bus puikus. Jei negalite naudoti „jQuery“, fotografavimo fazėje galite naudoti blur :

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

Be to, daugeliui dialogų jums reikės leisti konteineriui sutelkti dėmesį. Pridėkite tabindex="-1" , kad dialogo >

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

Jei žaidžiate su šia demonstracija ilgiau nei minutę, turėtumėte greitai ieškoti problemų.

Pirma, dialogo >focusout įvykį prieš focusin pradedant focusout įvykį.

Taisymas yra būsenos eilutė įvykių cikle. Tai galima padaryti naudodami setImmediate(...) arba setTimeout(..., 0) naršyklėms, kurios nepalaiko „ setImmediate . Kai jis yra eilėje, jį galima atšaukti paskesniu focusin :

 $('.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> 

Antroji problema yra ta, kad dialogas nebus uždaromas, kai dar kartą spustelėsite nuorodą. Taip yra dėl to, kad dialogas netenka dėmesio ir dėl to uždaromas, po to spustelėjus nuorodą, dialogas atsidaro.

Kaip ir ankstesniame leidime, reikia valdyti fokusavimo būseną. Atsižvelgiant į tai, kad būsenos pasikeitimas jau yra eilėje, tai tik dėmesio įvykių apdorojimo interaktyviu režimu klausimas:

Ji turėtų atrodyti pažįstama.
 $('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> 

„Esc“ klavišas

Jei manote, kad viskas padaryta valdant fokusavimo būsenas, galite padaryti daugiau, kad supaprastintumėte vartotojo patirtį.

Tai dažnai „malonu turėti“, tačiau paprastai atsitinka, kai turite modalinį arba pop-up failą bet kokio tipo, kuris jį uždaro „ Esc“ klavišu .

 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> 

Jei žinote, kad dialogo >

 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. 

WAI-ARIA funkcijos ir kita prieinamumo parama

Tikiuosi, kad šis atsakymas apims šios funkcijos pagrindinį klaviatūros ir pelės palaikymo pagrindą, tačiau kadangi tai jau gana reikšminga, nesiruošsiu aptarti WAI-ARIA funkcijų ir atributų , tačiau rekomenduoju, kad kūrėjai išsamiau susipažintų su specifikacija vaidmenis, kuriuos jie turi naudoti, ir kitus svarbius atributus.

220
12 июля '16 в 2:29 2016-07-12 02:29 atsakymas pateikiamas zzzzBov liepos 12, 16 d., 02:29, 2016-07-12 02:29

Kiti čia esantys sprendimai man neveikė, todėl turėjau naudoti:

 if(!$(event.target).is('#foo')) { // hide menu } 
132
07 июля '09 в 2:10 2009-07-07 02:10 atsakymas Dennisui pateiktas liepos 07 d., 09:10 2009-07-07 02:10

Turiu programą, kuri veikia panašiai kaip Erano pavyzdys, išskyrus tai, kad atidarydamas meniu ... pridedu paspaudimo įvykį prie kūno ...

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

Daugiau informacijos apie jQuery one() funkciją

122
30 сент. Joe Lencioni atsakymas rugsėjo 30 d 2008-09-30 21:13 '08 at 9:13 pm 2008-09-30 21:13
 $("#menuscontainer").click(function() { $(this).focus(); }); $("#menuscontainer").blur(function(){ $(this).hide(); }); 

Dirba man puikiai.

36
17 нояб. Atsakymą pateikė vartotojo212621 lapkritis 17. 2009-11-17 09:13 '09, 9:13 2009-11-17 09:13

Dabar yra papildinys: išoriniai įvykiai ( dienoraščio įrašas )

Toliau nurodoma, kai paspaudimo (WLOG) tvarkytojas yra susietas su elementu:

  • elementas pridedamas prie masyvo, kuriame yra visi elementai su paspaudimų šalinimo tvarkytojais.
  • ( pavadintas ) paspaudimo tvarkytojas yra susietas su dokumentu (jei jis dar nėra)
  • bet kokiu paspaudimu dokumente paspaudimų įvykis yra įvykdomas tiems šio masyvo elementams, kurie nėra lygūs arba tikslinio paspaudimo pagrindinis objektas
  • Be to, įvykio „clickoutside“ įvykis yra nustatytas į elementą, kurį vartotojas spustelėjo (todėl jūs net žinote, kad vartotojas spustelėjo, o ne tik, kad jis spustelėjo išorėje).

Taigi, dėl dauginimo nėra jokių įvykių, o papildomi paspaudimų tvarkytojai gali būti naudojami „aukščiau“ išorės tvarkytojo pagalba.

35
05 апр. Wolframo atsakymas 2010-04-05 13:07 '10, 13:07, 2010-04-05 13:07

Ištyręs tris darbo sprendimus (pamiršo nuorodas į puslapius)

Pirmasis sprendimas

 <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> 

Antrasis sprendimas

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

Trečiasis sprendimas

 <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 нояб. atsakymas pateikiamas Rameez Rami 02 lapkričio. 2015-11-02 11:33 '15 at 11:33 2015-11-02 11:33

Jis puikiai dirbo man!

 $('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 atsakymas duotas srinath 04 birželio 12 d. 17:08 2012-06-04 17:08

Nemanau, kad jums tikrai reikia uždaryti meniu, kai vartotojas spusteli jį; jums reikia meniu, kad uždarytumėte, kai vartotojas spusteli bet kurioje puslapio vietoje. Jei spustelėsite meniu arba išorinį meniu, ar jis uždaromas teisingai?

Nepavykus rasti tinkamų atsakymų, paprašiau parašyti šį dienoraštį kitą dieną. Jei norite, kad būtų daugiau pedantų, yra keletas klaidų, į kurias reikia atkreipti dėmesį:

  • Jei spustelėję prie kūno elemento pridedate paspaudimo įvykio tvarkytoją, prieš uždarydami meniu ir palaukite įvykį, palaukite, kol paspaudžiate antrą paspaudimą. Priešingu atveju, paspaudimo įvykis, atidaręs meniu, bus rodomas klausytojo ekrane, kuris turėtų uždaryti meniu.
  • Jei paspaudimo įvykyje naudosite event.stopPropogation (), jokie kiti jūsų puslapio elementai negali turėti paspaudimo, kur uždaryti funkciją.
  • Paspaudimo įvykio tvarkytojo pritvirtinimas prie kūno elemento yra neribotas, nėra veiksmingas sprendimas.
  • Lyginant įvykio tikslą su tėvais su prižiūrėtojo kūrėju, manote, kad norite uždaryti meniu, kai jį spustelėsite, kai tai, ką tikrai norite uždaryti, kai spustelėsite bet kurioje puslapio vietoje.
  • Klausydamiesi kūno elementų įvykių jūsų kodas taps trapesnis. Stilius yra nekaltas, nes jis gali sulaužyti: 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 atsakymas pateikiamas 34m0 gegužės 19, '11, 0:15 2011-05-19 00:15

Kaip dar vienas plakatas, sakoma, kad yra daug klaidų, ypač jei rodomas elementas (šiuo atveju meniu) turi interaktyvių elementų. Radau, kad šis metodas yra gana patikimas:

 $('#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 дек. Benb atsakymas, pateiktas gruodžio 22 d 2011-12-22 14:59 '11, 14:59, 2011-12-22 14:59

Paprastas situacijos sprendimas yra:

 $(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(); } }); 

Pirmiau minėtas scenarijus paslėps div jei bus divdiv click“ įvykio laukas.

Norėdami gauti daugiau informacijos, žr. Šį tinklaraštį: http://www.codecanal.com/detect-click-outside-div-using-javascript/

20
15 дек. Atsakymą pateikė Jitendra Damor gruodžio 15 d. 2015-12-15 06:50 '15 at 6:50 2015-12-15 06:50

Patikrinkite >

Arba patikrinkite paspaudimo padėtį ir patikrinkite, ar jis yra meniu srityje.

18
30 сент. Chris MacDonald atsakymas, pateiktas rugsėjo 30 d 2008-09-30 16:20 '08 at 4:20 pm 2008-09-30 16:20

Sprendimas1

Užuot naudoję event.stopPropagation (), kuri gali turėti tam tikrų šalutinių efektų, tiesiog nustatykite paprastą vėliavos kintamąjį ir pridėkite vieną, if sąlyga. Aš išbandžiau ir dirbau puikiai be jokių šalutinių stopPropagation efektų:

 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"; } }); 

Sprendimas2

Naudojant paprastą, if sąlyga:

 $(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 янв. Atsakyti Iman Sedighi 28 sausis 2015-01-28 20:24 '15 ne 20:24 2015-01-28 20:24

Man pavyko kažką panašaus:

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

Logika yra tokia: kai rodomas #menuscontainer , #menuscontainer paspaudimo #menuscontainer su kūnu, kuris slepia #menuscontainer tik tuo atveju, jei taikinys (paspaudimas) nėra vaikas.

15
02 дек. Atsakymą pateikė Chu Yeow 02 Dec. 2010-12-02 12:53 '10, 12:53, 2010-12-02 12:53

Kaip alternatyvą:

 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(); } }); 

Jis neturi problemų sustabdyti įvykių pasiskirstymą ir geriau išlaikyti kelis meniu tame pačiame puslapyje, kur pirmą kartą atidarius antrajame meniu bus paliktas pirmasis atradimas „stopPropagation“ sprendime.

14
24 июля '14 в 12:41 2014-07-24 12:41 Atsakymą pateikė Bohdan Lyzanets , liepos 24 d., 14 d., 12:41 2014-07-24 12:41

Radau šį metodą kai kuriuose jQuery kalendoriaus įskiepiuose.

 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 atsakymą pateikė „ nazar kuliyev“ liepos 28 d. 11 d. 17:06 2011-07-28 17:06

Štai vanilės javascript sprendimas būsimiems žiūrovams.

Paspaudus bet kurį dokumento elementą, jei paspaudžiamas paspaudžiamas elemento identifikatorius arba paslėptas elementas nėra paslėptas, o paslėptas elementas neturi elemento su spustelėjimu, perjunkite elementą.

 (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); })(); 

Jei tame pačiame puslapyje ketinate įjungti kelis jungiklius, galite naudoti kažką panašaus:

  • Pridėkite atlenkiamam elementui hidden klasės pavadinimą.
  • Spustelėję dokumentą uždarykite visus paslėptus elementus, kuriuose nėra elemento su paspaudimu ir nėra paslėpti.
  • Jei spustelėjęs elementas yra jungiklis, perjunkite nurodytą elementą.

10
20 мая '15 в 1:52 2015-05-20 01:52 atsakymas į Tiny Giant pateikiamas gegužės 15 d. 15 val. 1:52 2015-05-20 01:52

Renginys turi nuosavybę, vadinamą elemento įvykio.path, kuris yra „statinis užsakytas visų protėvių sąrašas medžio tvarkoje“. Norėdami patikrinti, ar įvykis įvyko iš konkretaus DOM elemento ar vieno iš jo vaikų elementų, tiesiog patikrinkite kelią į tą konkrečią DOM elementą. Ją taip pat galima naudoti norint patikrinti keletą loginio OR elementų, kai tikrinama some funkcijos elementas.

 #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");