Pytanie Jak wykryć kliknięcie poza elementem?


Mam kilka menu HTML, które wyświetlają się całkowicie, gdy użytkownik kliknie w nagłówek tych menu. Chciałbym ukryć te elementy, gdy użytkownik kliknie poza obszarem menu.

Czy coś takiego jest możliwe dzięki jQuery?

$("#menuscontainer").clickOutsideThisElement(function() {
    // Hide the menus
});

2027


pochodzenie


Oto przykład tej strategii: jsfiddle.net/tedp/aL7Xe/1 - Ted
Jak wspomniał Tom, będziesz chciał przeczytać css-tricks.com/dangers-stopping-event-propagation przed użyciem tego podejścia. To narzędzie jsfiddle jest całkiem fajne. - Jon Coombs
uzyskaj odwołanie do elementu, a następnie event.target, a na końcu! = lub == oba z nich następnie wykonaj odpowiedni kod. - Rohit Kumar
Polecam użycie github.com/gsantiago/jquery-clickout :) - Rômulo M. Farias
Spróbuj użyć event.path. http://stackoverflow.com/questions/152975/how-do-i-detect-a-click-outside-an-element/43405204#43405204 - Dan Philip


Odpowiedzi:


UWAGA: Korzystanie stopEventPropagation() jest czymś, czego należy unikać, ponieważ łamie normalny przepływ zdarzeń w DOM. Widzieć Ten artykuł po więcej informacji. Rozważ użycie Ta metoda zamiast.

Dołącz zdarzenie kliknięcia do treści dokumentu, który zamyka okno. Dołącz oddzielne zdarzenie kliknięcia do kontenera, który zatrzymuje propagację do treści dokumentu.

$(window).click(function() {
//Hide the menus if visible
});

$('#menucontainer').click(function(event){
    event.stopPropagation();
});

1620



Łamie to standardowe zachowanie wielu rzeczy, w tym przycisków i linków, zawartych w #menucontainer. Jestem zaskoczony, że ta odpowiedź jest tak popularna. - Art
Nie narusza to zachowania niczego wewnątrz #menucontainer, ponieważ znajduje się na samym dole łańcucha propagacji dla czegokolwiek w środku. - Eran Galperin
jest bardzo piękna, ale powinieneś jej użyć $('html').click() nie ciało. Ciało zawsze ma wysokość swojej zawartości. Nie ma zbyt wiele treści lub ekran jest bardzo wysoki, działa tylko na części wypełnionej ciałem. - meo
Jestem również zaskoczony, że to rozwiązanie zyskało tak wiele głosów. To nie powiedzie się dla żadnego elementu na zewnątrz, który ma stopPropagation jsfiddle.net/Flandre/vaNFw/3 - Andre
Philip Walton wyjaśnia bardzo dobrze, dlaczego ta odpowiedź nie jest najlepszym rozwiązaniem: css-tricks.com/dangers-stopping-event-propagation - Tom


Możesz słuchać a Kliknij wydarzenie w dniu document i upewnij się #menucontainer nie jest przodkiem lub celem klikniętego elementu przy użyciu .closest().

Jeśli tak nie jest, kliknięty element znajduje się poza #menucontainer i możesz bezpiecznie to ukryć.

$(document).click(function(event) { 
    if(!$(event.target).closest('#menucontainer').length) {
        if($('#menucontainer').is(":visible")) {
            $('#menucontainer').hide();
        }
    }        
});

Edycja - 2017-06-23

Możesz także posprzątać po detektorze zdarzeń, jeśli planujesz zwolnić menu i chcesz przestać słuchać wydarzeń. Ta funkcja oczyści tylko nowo utworzony obiekt nasłuchujący, zachowując inne detektory kliknięć document. Ze składnią ES2015:

export function hideOnClickOutside(selector) {
  const outsideClickListener = (event) => {
    if (!$(event.target).closest(selector).length) {
      if ($(selector).is(':visible')) {
        $(selector).hide()
        removeClickListener()
      }
    }
  }

  const removeClickListener = () => {
    document.removeEventListener('click', outsideClickListener)
  }

  document.addEventListener('click', outsideClickListener)
}

Edytuj - 2018-03-11

Dla tych, którzy nie chcą używać jQuery. Oto powyższy kod w zwykłym vanillaJS (ECMAScript6).

function hideOnClickOutside(element) {
    const outsideClickListener = event => {
        if (!element.contains(event.target)) { // or use: event.target.closest(selector) === null
            if (isVisible(element)) {
                element.style.display = 'none'
                removeClickListener()
            }
        }
    }

    const removeClickListener = () => {
        document.removeEventListener('click', outsideClickListener)
    }

    document.addEventListener('click', outsideClickListener)
}

const isVisible = elem => !!elem && !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ) // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js 

UWAGA: Opiera się to na komentarzu Alexa, którego należy użyć !element.contains(event.target) zamiast części jQuery.

Ale element.closest() jest teraz dostępny również we wszystkich głównych przeglądarkach (wersja W3C różni się nieco od wersji jQuery). Polyfills można znaleźć tutaj: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest


1127



Próbowałem wielu innych odpowiedzi, ale tylko ten zadziałał. Dzięki. Kod, który wykorzystałem, był następujący: $ (document) .click (function (event) {if ($ (event.target) .closest (". Window") length == 0) {$ (". Window" ) .fadeOut ("szybko");}}); - Pistos
Tak naprawdę skończyło się na tym rozwiązaniu, ponieważ lepiej obsługuje wiele menu na tej samej stronie, gdzie kliknięcie drugiego menu, gdy pierwszy jest otwarty, pozostawi pierwsze otwarte w rozwiązaniu stopPropagation. - umassthrower
To bardzo dobre rozwiązanie dla wielu elementów na stronie. - jsgroove
Doskonała odpowiedź. To jest sposób, aby przejść, gdy masz wiele przedmiotów, które chcesz zamknąć. - John
Bez jQuery - !element.contains(event.target) za pomocą Node.contains () - Alex Ross


Jak wykryć kliknięcie poza elementem?

Powód, dla którego to pytanie jest tak popularne i ma tak wiele odpowiedzi, jest zwodniczo złożony. Po prawie ośmiu latach i dziesiątkach odpowiedzi, jestem naprawdę zaskoczony, widząc, jak mało uwagi poświęcono dostępności.

Chciałbym ukryć te elementy, gdy użytkownik kliknie poza obszarem menu.

Jest to szlachetna przyczyna i jest rzeczywisty kwestia. Tytuł pytania - na którym większość odpowiedzi wydaje się próbować adresować - zawiera niefortunny czerwony śledzia.

Podpowiedź: to jest to słowo "Kliknij"!

W rzeczywistości nie chcesz wiązać procedur obsługi kliknięć.

Jeśli wiążą się z nimi moduły obsługi kliknięć, aby zamknąć okno dialogowe, już się nie udało. Powodem, dla którego się nie udało, jest to, że nie wszyscy się uruchamiają click wydarzenia. Użytkownicy, którzy nie używają myszy, będą mogli opuścić okno dialogowe (a wyskakujące menu jest prawdopodobnie typem okna dialogowego), naciskając Patka, a następnie nie będą mogli odczytać treści za dialogiem bez późniejszego wywoływania click zdarzenie.

Zmieńmy zatem pytanie.

Jak zamknąć okno dialogowe, gdy użytkownik skończy z nim?

To jest cel. Niestety, teraz musimy związać userisfinishedwiththedialog zdarzenie, a to wiązanie nie jest tak proste.

Jak więc możemy wykryć, że użytkownik zakończył korzystanie z okna dialogowego?

focusout zdarzenie

Dobrym początkiem jest ustalenie, czy fokus opuścił okno dialogowe.

Podpowiedź: bądź ostrożny z blur zdarzenie, blur nie rozprzestrzenia się, jeśli wydarzenie zostało powiązane z fazą propagacji!

jQuery's focusout wszystko będzie dobrze. Jeśli nie możesz użyć jQuery, możesz użyć blur w fazie przechwytywania:

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

Ponadto w przypadku wielu okien dialogowych musisz pozwolić kontenerem na skupienie się. Dodaj tabindex="-1" aby umożliwić dynamiczne otrzymywanie dialogu bez zakłócania przepływu tabulatora.

$('a').on('click', function () {
  $(this.hash).toggleClass('active').focus();
});

$('div').on('focusout', function () {
  $(this).removeClass('active');
});
div {
  display: none;
}
.active {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
  Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>


Jeśli grasz z tym demo dłużej niż minutę, powinieneś szybko zacząć widzieć problemy.

Po pierwsze, link w oknie dialogowym nie jest klikalny. Próba kliknięcia na nią lub zakładki spowoduje zamknięcie okna dialogowego przed rozpoczęciem interakcji. Dzieje się tak dlatego, że skupienie elementu wewnętrznego wyzwala a focusout zdarzenie przed wyzwoleniem focusin wydarzenie ponownie.

Poprawka polega na kolejkowaniu zmiany stanu w pętli zdarzeń. Można tego dokonać za pomocą setImmediate(...), lub setTimeout(..., 0) dla przeglądarek, które nie obsługują setImmediate. Po umieszczeniu w kolejce może zostać anulowane przez kolejne 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'));
  }
});

$('a').on('click', function () {
  $(this.hash).toggleClass('active').focus();
});

$('div').on({
  focusout: function () {
    $(this).data('timer', setTimeout(function () {
      $(this).removeClass('active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this).data('timer'));
  }
});
div {
  display: none;
}
.active {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
  Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>

Drugą kwestią jest to, że okno dialogowe nie zamknie się po ponownym naciśnięciu łącza. Dzieje się tak dlatego, że okno dialogowe traci ostrość, powodując bliskie zachowanie, po którym kliknięcie łącza uruchamia ponowne otwarcie okna dialogowego.

Podobnie jak w poprzednim wydaniu, stanem skupienia należy zarządzać. Biorąc pod uwagę, że zmiana stanu została już ustawiona w kolejce, jest to tylko kwestia obsługi zdarzeń fokusowych w wyzwalaczach okna dialogowego:

To powinno wyglądać znajomo
$('a').on({
  focusout: function () {
    $(this.hash).data('timer', setTimeout(function () {
      $(this.hash).removeClass('active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this.hash).data('timer'));  
  }
});

$('a').on('click', function () {
  $(this.hash).toggleClass('active').focus();
});

$('div').on({
  focusout: function () {
    $(this).data('timer', setTimeout(function () {
      $(this).removeClass('active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this).data('timer'));
  }
});

$('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;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
  Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>


wyjście klawisz

Jeśli sądzisz, że zostały wykonane przez obsługę stanów skupienia, możesz zrobić więcej, aby uprościć obsługę.

Często jest to funkcja "miło mieć", ale często jest tak, że gdy masz modal lub popup dowolnego rodzaju, który wyjście klucz to zamknie.

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

$('a').on('click', function () {
  $(this.hash).toggleClass('active').focus();
});

$('div').on({
  focusout: function () {
    $(this).data('timer', setTimeout(function () {
      $(this).removeClass('active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this).data('timer'));
  },
  keydown: function (e) {
    if (e.which === 27) {
      $(this).removeClass('active');
      e.preventDefault();
    }
  }
});

$('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;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
  Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>


Jeśli wiesz, że w oknie dialogowym masz elementy, które można ustawić, nie musisz bezpośrednio ustawiać ostrości w oknie dialogowym. Jeśli tworzysz menu, możesz zamiast niego ustawić pierwszy element menu.

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

$('.menu__link').on({
  click: function (e) {
    $(this.hash)
      .toggleClass('submenu--active')
      .find('a:first')
      .focus();
    e.preventDefault();
  },
  focusout: function () {
    $(this.hash).data('submenuTimer', setTimeout(function () {
      $(this.hash).removeClass('submenu--active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this.hash).data('submenuTimer'));  
  }
});

$('.submenu').on({
  focusout: function () {
    $(this).data('submenuTimer', setTimeout(function () {
      $(this).removeClass('submenu--active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this).data('submenuTimer'));
  },
  keydown: function (e) {
    if (e.which === 27) {
      $(this).removeClass('submenu--active');
      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;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="menu">
  <li class="menu__item">
    <a class="menu__link" href="#menu-1">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</a> sit amet.


Role WAI-ARIA i inne ułatwienia dostępu

Ta odpowiedź, mam nadzieję, obejmuje podstawy dostępnej obsługi klawiatury i myszy dla tej funkcji, ale ponieważ jest już dość spora, unikam dyskusji Role i atrybuty WAI-ARIA, Jednakże, ja wysoko zalecamy, aby osoby wdrażające odwoływały się do specyfikacji, aby uzyskać szczegółowe informacje na temat ról, które powinny pełnić, oraz wszelkich innych odpowiednich atrybutów.


188



Jest to najbardziej kompletna odpowiedź, mając na uwadze wyjaśnienia i dostępność. Myślę, że powinna to być akceptowana odpowiedź, ponieważ większość innych odpowiedzi obsługuje tylko kliknięcie i jest po prostu fragmentem kodu upuszczonym bez żadnych wyjaśnień. - Cyrille
Niesamowite, dobrze wyjaśnione. Po prostu użyłem tego podejścia w React Component i działałem doskonale dzięki - David Lavieri
@zzzzBov dzięki za głęboką odpowiedź, próbuję osiągnąć to w waniliowym JS, i jestem trochę zagubiony z wszystkimi rzeczami jquery. czy jest coś podobnego w jilli waniliowej? - HendrikEng
@zzzzBov Nie, nie chcę, abyś napisał wersję bez jQuery oczywiście, postaram się to zrobić i myślę, że najlepiej jest zadać nowe pytanie tutaj, jeśli naprawdę utknąłem. Wielkie dzięki. - HendrikEng
Chociaż jest to świetna metoda wykrywania klikania niestandardowych rozwijanych lub innych danych wejściowych, nigdy nie powinna być preferowaną metodą dla modów lub popupów z dwóch powodów. Modal zostanie zamknięty, gdy użytkownik przełączy się na inną kartę lub okno lub otworzy menu kontekstowe, które jest naprawdę irytujące. Dodatkowo zdarzenie "kliknięcie" uruchamia się myszką w górę, a zdarzenie "focusout" wyzwala natychmiast po naciśnięciu przycisku myszy. Zwykle przycisk wykonuje czynność tylko po naciśnięciu przycisku myszy i zwolnieniu. Właściwym, dostępnym sposobem na zrobienie tego dla modałów jest dodanie tabulowanego przycisku zamykania. - Kevin


Inne rozwiązania tutaj nie działały dla mnie, więc musiałem użyć:

if(!$(event.target).is('#foo'))
{
    // hide menu
}

127



Opublikowaliśmy kolejny praktyczny przykład użycia event.target, aby uniknąć uruchamiania innego widżetu interfejsu Jquery z zewnętrznymi przyciskami obsługi html podczas osadzania ich we własnym oknie pop-over: Najlepszy sposób na zdobycie oryginalnego celu - Joey T
To działało dla mnie, z wyjątkiem tego, co dodałem && !$(event.target).parents("#foo").is("#foo") w środku IF instrukcja, aby wszystkie elementy podrzędne nie zamknęły menu po kliknięciu. - honyovk
@Frug Twoja odpowiedź może być cenna, więc masz 5, ale jestem zmieszany twoją odpowiedzią. i kto jest MBJ. Szukałem lepszego rozwiązania na podstawie Twojej odpowiedzi. - Satya Prakash
MBJ to prawdopodobnie stara osoba, która opublikowała komentarz tuż nad moją. Użytkownicy zmieniają nazwy, może to utrudnić, ale zauważ, że komentarz powyżej mojego ma dodane .parents("#foo") - Frug
Należy użyć zwięzłego udoskonalenia w zakresie obsługi głębokiego zagnieżdżania .is('#foo, #foo *'), ale Nie polecam wiązania programów obsługi kliknięć w celu rozwiązania tego problemu. - zzzzBov


Mam aplikację, która działa podobnie do przykładu Erana, z tym wyjątkiem, że dołączam zdarzenie click do ciała po otwarciu menu ... Kinda w ten sposób:

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

  event.stopPropagation();
});

Więcej informacji na temat jQuery's one() funkcjonować


118



ale jeśli klikniesz na menu, a potem na zewnątrz, to nie zadziała :) - vsync
Pomaga umieścić event.stopProgagantion () przed powiązaniem detektora kliknięć z treścią. - Jasper Kennis
Problem polega na tym, że "jeden" dotyczy metody jQuery dodawania zdarzeń do tablicy wiele razy. Jeśli więc klikniesz menu, aby otworzyć je więcej niż raz, wydarzenie zostanie ponownie powiązane z ciałem i będzie próbowało kilkakrotnie ukryć menu. Aby naprawić ten problem, należy zastosować procedurę failsafe. - marksyzm
Po związaniu za pomocą .one - wewnątrz $('html') handler - napisz a $('html').off('click'). - Cody
@Cody Nie sądzę, że to pomaga. The one Handler automatycznie zadzwoni off (jak to pokazano w dokumentach jQuery). - Mariano Desanze


$("#menuscontainer").click(function() {
    $(this).focus();
});
$("#menuscontainer").blur(function(){
    $(this).hide();
});

Działa dla mnie dobrze.


32



To jest ten, którego bym użył. Może nie być idealny, ale jako programista hobbistyczny jest na tyle prosty, że można go wyraźnie zrozumieć. - kevtrout
rozmycie jest ruchem poza #menucontainer pytanie dotyczyło kliknięcia - borrel
rozmycie @borrel jest nie ruch poza pojemnikiem. Blur jest przeciwieństwem ostrości, myślisz o mouseout. To rozwiązanie sprawdziło się szczególnie dobrze, gdy tworzyłem tekst "kliknij, aby edytować", w którym zamieniłem tekst na zwykły tekst i pola wprowadzania na kliknięcia. - parker.sikand
Musiałem dodać tabindex="-1" do #menuscontainer aby to działało. Wydaje się, że jeśli włożysz etykietę wejściową do pojemnika i klikniesz na nią, pojemnik zostanie ukryty. - tyrion
zdarzenie mouseleave jest bardziej odpowiednie dla menu i kontenerów (zob. w3schools.com/jquery/...) - Evgenia Manolova


Teraz jest wtyczka do tego: wydarzenia zewnętrzne (post na blogu)

Następujące czynności występują, gdy clickoutside handler (WLOG) jest związany z elementem:

  • element jest dodawany do tablicy, która zawiera wszystkie elementy clickoutside obsługi
  • a (z nazwami) Kliknij przewodnik jest związany z dokumentem (jeśli jeszcze tam nie jest)
  • na każdym Kliknij w dokumencie, clickoutside Zdarzenie jest wyzwalane dla tych elementów w tej tablicy, które nie są równe lub są elementami nadrzędnymi Kliknij- wymusza cel
  • dodatkowo event.target dla clickoutside Zdarzenie jest ustawione na element, który użytkownik kliknął (dzięki czemu nawet wiesz, co kliknął użytkownik, a nie tylko, że kliknął na zewnątrz)

Więc żadne zdarzenia nie są zatrzymywane z propagacji i dodatkowe Kliknij handlerów można używać "powyżej" elementu z zewnętrznym treserem.


31



Niezła wtyczka. Link do "wydarzeń zewnętrznych" jest martwy, natomiast link do postu na blogu jest wciąż żywy i zapewnia bardzo przydatną wtyczkę dla zdarzeń rodzaju "kliknięcie". To także licencja MIT. - TechNyquist
Świetna wtyczka. Działa doskonale. Sposób użycia jest następujący: $( '#element' ).on( 'clickoutside', function( e ) { .. } ); - Gavin


To zadziałało idealnie !!

$('html').click(function (e) {
    if (e.target.id == 'YOUR-DIV-ID') {
        //do something
    } else {
        //do something
    }
});

26



To rozwiązanie sprawdziło się w tym, co robiłem, dzięki czemu nadal potrzebowałem zdarzenia kliknięcia, aby się przepalić, dzięki. - Mike


Po badaniach znalazłem trzy działające rozwiązania (zapomniałem o odnośnikach do stron)

Pierwsze rozwiązanie

<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');
            /* Hide element here */
        }
        else {
            clickFlag=0;
        }
    });
    $('body').on('click','#testDiv', function (event) {
        clickFlag = 1;
        console.log('showed the element');
        /* Show the element */
    });
</script>

Drugie rozwiązanie

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

Trzecie rozwiązanie

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

25



Trzecie rozwiązanie jest zdecydowanie najbardziej eleganckim sposobem sprawdzania. Nie wiąże się również z żadnym obciążeniem jQuery. Bardzo dobrze. To bardzo pomogło. Dzięki. - dbarth
Próbuję uzyskać trzecie rozwiązanie z wieloma elementami document.getElementsByClassName, jeśli ktoś ma wskazówkę, podziel się. - lowtechsun
@lowtechsun Musisz sprawdzić, czy każdy z nich jest w pętli. - Donnie D'Amato
Naprawdę podobało mi się trzecie rozwiązanie, jednak kliknięcie uruchamia się, zanim mój div zacznie pokazywać, który ukrywa go ponownie, czy jest jakiś pomysł, dlaczego? - indiehjaerta


Nie sądzę, aby naprawdę potrzebne było zamknięcie menu, gdy użytkownik kliknie na zewnątrz; potrzebne jest zamknięcie menu, gdy użytkownik kliknie w dowolnym miejscu na stronie. Jeśli klikniesz na menu, lub z menu, powinno zamknąć się prawo?

Znalezienie niezadowalających odpowiedzi powyżej skłoniło mnie do napisania ten wpis na blogu innego dnia. Dla bardziej pedantycznych, istnieje kilka gotch, aby zwrócić uwagę na:

  1. Jeśli dołączasz obsługę zdarzeń kliknięcia do elementu body w czasie kliknięcia, pamiętaj, aby poczekać na drugie kliknięcie przed zamknięciem menu i odłączyć wydarzenie. W przeciwnym razie zdarzenie click, które otworzyło menu, będzie bańką do słuchacza, który musi zamknąć menu.
  2. Jeśli korzystasz z event.stopPropogation () w przypadku zdarzenia kliknięcia, żadne inne elementy na Twojej stronie nie mogą mieć funkcji "kliknij, aby zamknąć".
  3. Dołączanie obsługi zdarzeń kliknięcia do elementu body w nieskończoność nie jest wydajnym rozwiązaniem
  4. Porównywanie celu zdarzenia i jego rodziców do twórcy przewodnika zakłada, że ​​chcesz zamknąć menu po kliknięciu, kiedy naprawdę chcesz je zamknąć, gdy klikniesz w dowolnym miejscu na stronie.
  5. Słuchanie zdarzeń na elemencie body sprawi, że twój kod będzie bardziej kruchy. Stylizacja tak niewinna, jak to złamałoby: body { margin-left:auto; margin-right: auto; width:960px;}

22



"Jeśli klikniesz na menu lub z menu, powinno zamknąć się prawo?" nie zawsze. Anulowanie kliknięcia poprzez przeciągnięcie elementu nadal będzie powodowało klikanie na poziomie dokumentu, ale intencją nie będzie kontynuowanie zamykania menu. Istnieje również wiele innych typów okien dialogowych, które mogą wykorzystywać zachowanie typu "kliknięcie", które umożliwia klikanie wewnętrznie. - zzzzBov