it-swarm.dev

Jak zjistím kliknutí mimo prvek?

Mám nějaké HTML menu, které jsem ukázat úplně, když uživatel klikne na hlavu těchto menu. Chtěl bych tyto prvky skrýt, když uživatel klikne mimo oblast nabídky.

Je něco takového možné s jQuery?

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

Poznámka: Použití stopEventPropagation() je něco, co by se mělo vyhnout, protože přeruší normální tok událostí v DOM. Více informací viz tento článek . Zvažte místo toho použít tuto metodu

Připojte událost klepnutí na tělo dokumentu, které zavře okno. Připojte samostatnou událost klepnutí do kontejneru, který zastaví šíření do těla dokumentu.

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

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

Můžete si poslechnout událost click v document a pak se ujistěte, že #menucontainer není předkem ani cílem prvku, na který jste klikli, pomocí .closest() .

Pokud tomu tak není, pak kliknutý prvek je mimo #menucontainer a můžete jej bezpečně skrýt.

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

Upravit - 2017-06-23

Můžete také vyčistit po posluchači události, pokud plánujete zavřít nabídku a chcete přestat poslouchat události. Tato funkce vymaže pouze nově vytvořený posluchač, přičemž zachová ostatní posluchače kliknutí na document. Se syntaxí ES2015:

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

Edit - 2018-03-11

Pro ty, kteří nechtějí používat jQuery. Zde je výše uvedený kód v jednoduché vanillaJS (ECMAScript6).

function hideOnClickOutside(element) {
    const outsideClickListener = event => {
        if (!element.contains(event.target) && isVisible(element)) { // or use: event.target.closest(selector) === null
          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 

POZNÁMKA: Toto je založeno na komentáři Alexa, aby místo části jQuery použil !element.contains(event.target).

element.closest() je nyní také k dispozici ve všech hlavních prohlížečích (verze W3C se liší od verze jQuery). Polyfills naleznete zde: https://developer.mozilla.org/en-US/ dokumenty/Web/API/Prvek/nejbližší

1228
Art

Jak detekovat kliknutí mimo prvek?

Důvodem, proč je tato otázka tak populární a má tolik odpovědí, je, že je klamně složitá. Po téměř osmi letech a desítkách odpovědí jsem opravdu překvapen, když jsem zjistil, jak málo je věnována přístupnost.

Chtěl bych tyto prvky skrýt, když uživatel klikne mimo oblast nabídky.

Toto je ušlechtilá příčina a je aktuální problém. Název otázky - což je to, co se většina odpovědí pokouší oslovit - obsahuje nešťastné červené sledě.

Tip: je to slovo "click" !

Ve skutečnosti nechcete vázat obsluhy kliknutí.

Pokud zavřete dialogové okno pro zavádění obsluhy kliknutí, neuspěli jste. Důvod, proč jste neuspěli, je skutečnost, že ne všichni spouští události clickname__. Uživatelé, kteří nepoužívají myš, budou moci uniknout z dialogového okna (a vyskakovací nabídka je pravděpodobně typem dialogu) stisknutím klávesy Tab, a pak nebudou moci číst obsah za dialogem bez následného spuštění události clickname__.

Pojďme si tedy otázku přeformulovat.

Jak lze zavřít dialog, když je uživatel dokončen?

To je cíl. Bohužel nyní musíme vázat událost userisfinishedwiththedialoga tato vazba není tak jednoduchá.

Jak tedy můžeme zjistit, že uživatel ukončil dialog?

focusoutudálost

Dobrým začátkem je určit, zda fokus opustil dialog.

Tip: buďte opatrní při události blurname__, blurse nešíří, pokud byla událost vázána na fázi probublávání

jQuery je focusoutNAME _ udělá dobře. Pokud nemůžete použít jQuery, můžete během fáze snímání použít blurname__:

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

Také pro mnoho dialogů budete potřebovat, aby kontejner získal fokus. Přidejte tabindex="-1", abyste dialogu umožnili dynamicky přijímat fokus, aniž by jinak přerušil tok tabbing.

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

Pokud hrajete s tímto demem déle než minutu, měli byste rychle začít vidět problémy.

První je, že odkaz v dialogu nelze kliknout. Pokus o kliknutí na něj nebo kartu na něj povede k uzavření dialogu před tím, než dojde k interakci. Je to proto, že fokusování vnitřního prvku spouští událost focusoutpřed opětovným spuštěním události focusinname__.

Oprava je fronta změny stavu na smyčce události. To lze provést pomocí setImmediate(...) nebo setTimeout(..., 0) pro prohlížeče, které nepodporují setImmediatename__. Po zařazení do fronty může být zrušeno následným focusinname__:

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

Druhým problémem je, že dialog se po opětovném stisknutí tlačítka nezavře. Důvodem je, že dialog ztrácí fokus, spouští chování při zavření, po kterém klepnutí na odkaz spustí dialog, aby se znovu otevřel.

Podobně jako v předchozím případě je třeba řídit stav zaostření. Vzhledem k tomu, že změna stavu již byla zařazena do fronty, je to jen otázka zpracování událostí fokusu v spouštěčích dialogu:

To by mělo vypadat dobře
$('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>

Esc klíč

Pokud jste si mysleli, že jste provedli práci se stavy zaostření, můžete udělat více pro zjednodušení uživatelského prostředí.

To je často "Nice to mít" funkce, ale je běžné, že když máte modální nebo popup jakéhokoli druhu, že Esc klíč zavře.

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>

Pokud víte, že máte v dialogovém okně zaostřitelné prvky, nebudete muset dialog přímo zaostřovat. Pokud vytváříte menu, můžete místo toho zaostřit na první položku nabídky.

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.

WAI-ARIA Role a další podpora usnadnění

Tato odpověď doufejme pokrývá základy dostupné podpory klávesnice a myši pro tuto funkci, ale protože je to již poměrně značné, vyhnu se diskusi o WAI-ARIA rolích a atributech , ale já vysoce doporučuje, aby implementátoři odkazovali na specifikaci pro podrobnosti o tom, jaké role by měli používat a další vhodné atributy.

248
zzzzBov

Jiná řešení zde pro mě nefungovala, takže jsem musel použít:

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

Mám aplikaci, která funguje podobně jako Eranův příklad, kromě toho, když připojím událost click k tělu, když otevřu menu ... Kinda like this:

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

  event.stopPropagation();
});

Další informace o funkci one() funkce jQuery

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

Pracuje pro mě v pohodě.

36
user212621

Nyní je k dispozici plugin: mimo události ( příspěvek do blogu )

Následující postup se stane, když je obslužný program clickoutside (WLOG) vázán na prvek:

  • prvek je přidán do pole, které obsahuje všechny prvky pomocí obslužných programů clickoutside
  • a ( namespaced ) click handler is bound to the document (if not already there)
  • na libovolném klepněte na tlačítko v dokumentu je událost clickoutside spuštěna pro ty prvky v tomto poli, které nejsou rovny cílovému cíli click -events.
  • navíc událost event.target pro událost clickoutside je nastavena na prvek, na který uživatel kliknul (takže víte, na co uživatel klikl, nikoli jen na to, že klikl mimo)

Takže žádné události nejsou zastaveny z propagace a další click ovladače mohou být použity "nad" prvkem s externím obslužným programem.

35
Wolfram

Po výzkumu jsem našel tři pracovní řešení (zapomněl jsem odkazy na stránky pro reference)

První řešení

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

Druhé řešení

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

Třetí řešení

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

To fungovalo pro mě dokonale!

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

Nemyslím si, že to, co opravdu potřebujete, je zavřít menu, když uživatel klikne venku; to, co potřebujete, je, aby se menu zavřelo, když uživatel na stránce klikne kdekoli. Pokud kliknete na nabídku, nebo z nabídky, měla by se zavřít vpravo? 

Nalezení neuspokojivých odpovědí mě přimělo napsat tento blog post druhý den. Pro více pedantické, tam je množství gotchas vzít si na vědomí:\t 

  1. Pokud připojíte obslužnou rutinu události klepnutí k prvku těla v době kliknutí, nezapomeňte před zavřením nabídky počkat na druhé kliknutí a zrušit vazbu na událost. V opačném případě se událost kliknutí, která otevřela nabídku, rozbliká na posluchače, který má nabídku zavřít.
  2. Pokud používáte event.stopPropogation () na události prokliků, žádné další prvky na vaší stránce nemohou mít funkci click -where-to-close.
  3. Připojení obsluhy události click k prvku těla na neurčito není výkonným řešením
  4. Porovnání cíle akce a jejích rodičů s tvůrcem psovoda předpokládá, že to, co chcete, je zavřít menu, když na něj kliknete, když to, co opravdu chcete, je zavřít, když kliknete kdekoliv na stránce.
  5. Poslech událostí na elementu těla bude váš kód křehčí. Styling jako nevinný, protože by to rozbilo: body { margin-left:auto; margin-right: auto; width:960px;}
24
34m0

Jako další plakát říkal, že existuje spousta gotchas, zejména pokud prvek, který zobrazujete (v tomto případě menu), má interaktivní prvky. Následující metoda byla poměrně robustní:

$('#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
benb

Jednoduchým řešením situace je:

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

Výše uvedený skript skryje div, pokud je spuštěna mimo událost div.

Další informace naleznete na následujícím blogu: http://www.codecanal.com/detect-click-outside-div-using-javascript/

20
Jitendra Damor

Řešení1

Namísto použití události event.stopPropagation (), která může mít některé vedlejší účinky, stačí definovat jednoduchou proměnnou příznaku a přidat jednu podmínku if. Testoval jsem to a pracoval bez jakýchkoliv vedlejších účinků 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";
    }
});

Řešení2

Pouze s jednoduchou podmínkou if:

$(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
Iman Sedighi

Zaškrtněte cíl události pro klepnutí na okno (mělo by se šířit do okna, pokud není nikde jinde zachyceno) a ujistěte se, že to není žádný z prvků nabídky. Pokud tomu tak není, pak jste mimo menu.

Nebo zkontrolujte polohu kliknutí a zjistěte, zda se nachází v oblasti nabídky.

18
Chris MacDonald

Měl jsem úspěch s něčím takovým:

var $menuscontainer = ...;

$('#trigger').click(function() {
  $menuscontainer.show();

  $('body').click(function(event) {
    var $target = $(event.target);

    if ($target.parents('#menuscontainer').length == 0) {
      $menuscontainer.hide();
    }
  });
});

Logika je: když je zobrazeno #menuscontainer, svázejte obslužný program pro klepnutí s tělem, které skrývá #menuscontainer pouze v případě, že cíl (kliknutí) není jeho dítětem.

15
Chu Yeow

Jako varianta:

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

Nemá žádný problém s zastavením propagace událostí a lépe podporuje více nabídek na stejné stránce, kde kliknutí na druhou nabídku, zatímco první je otevřená, ponechá první otevřené v řešení stopPropagation.

14
Bohdan Lyzanets

Našel jsem tuto metodu v nějakém pluginu 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
nazar kuliyev

Událost má vlastnost nazvanou event.path prvku, který je "staticky uspořádaný seznam všech jeho předků ve stromovém pořadí" . Chcete-li zkontrolovat, zda událost pochází z konkrétního prvku DOM nebo jednoho z jeho dětí, zkontrolujte cestu pro tento konkrétní prvek DOM. Lze jej také použít ke kontrole více prvků logickou ORing kontrolou prvku v some funkci.

$("body").click(function() {
  target = document.getElementById("main");
  flag = event.path.some(function(el, i, arr) {
    return (el == target)
  })
  if (flag) {
    console.log("Inside")
  } else {
    console.log("Outside")
  }
});
#main {
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main">
  <ul>
    <li>Test-Main</li>
    <li>Test-Main</li>
    <li>Test-Main</li>
    <li>Test-Main</li>
    <li>Test-Main</li>
  </ul>
</div>
<div id="main2">
  Outside Main
</div>

Takže pro váš případ To by mělo být 

$("body").click(function() {
  target = $("#menuscontainer")[0];
  flag = event.path.some(function(el, i, arr) {
    return (el == target)
  });
  if (!flag) {
    // Hide the menus
  }
});
10
Dan Philip

Zde je Vanilla JavaScript řešení pro budoucí diváky.

Po klepnutí na libovolný prvek v dokumentu, pokud je id prvku kliknutého prvku přepnut nebo skrytý prvek není skrytý a skrytý prvek neobsahuje prvek, na který se kliknul, přepněte prvek.

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

(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);
})();
<a href="javascript:void(0)" id="toggle">Toggle Hidden Div</a>
<div id="hidden" style="display: none;">This content is normally hidden. click anywhere other than this content to make me disappear</div>

Pokud chcete mít na stejné stránce více přepínačů, můžete použít něco takového:

  1. Přidejte název třídy hidden do skládací položky.
  2. Po klepnutí na dokument zavřete všechny skryté prvky, které neobsahují prvek, na který jste klikli, a nejsou skryté
  3. Je-li prvek, na který kliknete, přepínač, přepněte zadaný prvek.

(function () {
    "use strict";
    var hiddenItems = document.getElementsByClassName('hidden'), hidden;
    document.addEventListener('click', function (e) {
        for (var i = 0; hidden = hiddenItems[i]; i++) {
            if (!hidden.contains(e.target) && hidden.style.display != 'none')
                hidden.style.display = 'none';
        }
        if (e.target.getAttribute('data-toggle')) {
            var toggle = document.querySelector(e.target.getAttribute('data-toggle'));
            toggle.style.display = toggle.style.display == 'none' ? 'block' : 'none';
        }
    }, false);
})();
<a href="javascript:void(0)" data-toggle="#hidden1">Toggle Hidden Div</a>
<div class="hidden" id="hidden1" style="display: none;" data-hidden="true">This content is normally hidden</div>
<a href="javascript:void(0)" data-toggle="#hidden2">Toggle Hidden Div</a>
<div class="hidden" id="hidden2" style="display: none;" data-hidden="true">This content is normally hidden</div>
<a href="javascript:void(0)" data-toggle="#hidden3">Toggle Hidden Div</a>
<div class="hidden" id="hidden3" style="display: none;" data-hidden="true">This content is normally hidden</div>

10
Tiny Giant

Namísto použití přerušení toku, události rozostření/zaostření nebo jakékoli jiné složité techniky stačí jednoduše přizpůsobit tok událostí s příbuzností prvku:

$(document).on("click.menu-outside", function(event){
    // Test if target and it's parent aren't #menuscontainer
    // That means the click event occur on other branch of document tree
    if(!$(event.target).parents().andSelf().is("#menuscontainer")){
        // Click outisde #menuscontainer
        // Hide the menus (but test if menus aren't already hidden)
    }
});

Chcete-li odstranit posluchače mimo událost, jednoduše:

$(document).off("click.menu-outside");
8
mems

Pokud jste skriptování pro IE a FF 3. * a chcete vědět, zda se kliknutí vyskytlo v určité oblasti, můžete také použít něco jako:

this.outsideElementClick = function(objEvent, objElement){   
var objCurrentElement = objEvent.target || objEvent.srcElement;
var blnInsideX = false;
var blnInsideY = false;

if (objCurrentElement.getBoundingClientRect().left >= objElement.getBoundingClientRect().left && objCurrentElement.getBoundingClientRect().right <= objElement.getBoundingClientRect().right)
    blnInsideX = true;

if (objCurrentElement.getBoundingClientRect().top >= objElement.getBoundingClientRect().top && objCurrentElement.getBoundingClientRect().bottom <= objElement.getBoundingClientRect().bottom)
    blnInsideY = true;

if (blnInsideX && blnInsideY)
    return false;
else
    return true;}
8
Erik

Použití:

var go = false;
$(document).click(function(){
    if(go){
        $('#divID').hide();
        go = false;
    }
})

$("#divID").mouseover(function(){
    go = false;
});

$("#divID").mouseout(function (){
    go = true;
});

$("btnID").click( function(){
    if($("#divID:visible").length==1)
        $("#divID").hide(); // Toggle
    $("#divID").show();
});
7
webenformasyon

Jsem překvapen, že nikdo focusout neuznal událost:

var button = document.getElementById('button');
button.addEventListener('click', function(e){
  e.target.style.backgroundColor = 'green';
});
button.addEventListener('focusout', function(e){
  e.target.style.backgroundColor = '';
});
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <button id="button">Click</button>
</body>
</html>

6
Jovanni G

V dokumentu zavěste posluchače události kliknutí. Uvnitř posluchače událostí se můžete podívat na objekt event , zejména na event.target a zjistit, který prvek byl kliknut:

$(document).click(function(e){
    if ($(e.target).closest("#menuscontainer").length == 0) {
        // .closest can help you determine if the element 
        // or one of its ancestors is #menuscontainer
        console.log("hide");
    }
});
6
Salman A
$(document).click(function() {
    $(".overlay-window").hide();
});
$(".overlay-window").click(function() {
    return false;
});

Pokud na dokument kliknete, skryjte daný prvek, pokud nekliknete na stejný prvek.

5
Rowan

Pro snadnější použití a výraznější kód jsem pro tento účel vytvořil plugin jQuery:

$('div.my-element').clickOut(function(target) { 
    //do something here... 
});

Poznámka: target je prvek, na který uživatel skutečně klikl. Zpětné volání je však stále prováděno v kontextu původního prvku, takže můžete využít toto jak byste očekávali v zpětném volání jQuery.

Zapojit:

$.fn.clickOut = function (parent, fn) {
    var context = this;
    fn = (typeof parent === 'function') ? parent : fn;
    parent = (parent instanceof jQuery) ? parent : $(document);

    context.each(function () {
        var that = this;
        parent.on('click', function (e) {
            var clicked = $(e.target);
            if (!clicked.is(that) && !clicked.parents().is(that)) {
                if (typeof fn === 'function') {
                    fn.call(that, clicked);
                }
            }
        });

    });
    return context;
};

Ve výchozím nastavení je posluchač události kliknutí umístěn do dokumentu. Pokud však chcete omezit rozsah posluchače událostí, můžete předat objekt jQuery představující prvek nadřazené úrovně, který bude nadřazeným rodičem, na který budou poslouchána kliknutí. To zabrání zbytečným posluchačům událostí na úrovni dokumentu. Je zřejmé, že to nebude fungovat, pokud dodaný rodičovský prvek není rodičem vašeho počátečního elementu. 

Použít takto:

$('div.my-element').clickOut($('div.my-parent'), function(target) { 
    //do something here...
});
5
Matt Goodwin

Takhle jsem to udělal v YUI 3:

// Detect the click anywhere other than the overlay element to close it.
Y.one(document).on('click', function (e) {
    if (e.target.ancestor('#overlay') === null && e.target.get('id') != 'show' && overlay.get('visible') == true) {
        overlay.hide();
    }
});

Kontroluji, zda předchůdce není kontejnerem prvku widgetu, 
pokud cílem není otevření widgetu/elementu, 
pokud widget/prvek, který chci zavřít, je již otevřen (ne tak důležitý).

5
Satya Prakash

Upvote pro nejoblíbenější odpověď, ale přidejte 

&& (e.target != $('html').get(0)) // ignore the scrollbar

takže kliknutí na posuvník neukrývá cílový prvek.

5
bbe

To by mělo fungovat:

$('body').click(function (event) {
    var obj = $(event.target);
    obj = obj['context']; // context : clicked element inside body
    if ($(obj).attr('id') != "menuscontainer" && $('#menuscontainer').is(':visible') == true) {
        //hide menu
    }
});
4
Bilal Berjawi

Funkce:

$(function() {
    $.fn.click_inout = function(clickin_handler, clickout_handler) {
        var item = this;
        var is_me = false;
        item.click(function(event) {
            clickin_handler(event);
            is_me = true;
        });
        $(document).click(function(event) {
            if (is_me) {
                is_me = false;
            } else {
                clickout_handler(event);
            }
        });
        return this;
    }
});

Používání:

this.input = $('<input>')
    .click_inout(
        function(event) { me.ShowTree(event); },
        function() { me.Hide(); }
    )
    .appendTo(this.node);

Funkce jsou velmi jednoduché:

ShowTree: function(event) {
    this.data_span.show();
}
Hide: function() {
    this.data_span.hide();
}
4
Neco

Použil jsem níže skript a hotovo s jQuery.

jQuery(document).click(function(e) {
    var target = e.target; //target div recorded
    if (!jQuery(target).is('#tobehide') ) {
        jQuery(this).fadeOut(); //if the click element is not the above id will hide
    }
})

Níže naleznete kód HTML

<div class="main-container">
<div> Hello I am the title</div>
<div class="tobehide">I will hide when you click outside of me</div>
</div>

Můžete si přečíst návod zde

4
Rinto George

Toto je moje řešení tohoto problému:

$(document).ready(function() {
  $('#user-toggle').click(function(e) {
    $('#user-nav').toggle();
    e.stopPropagation();
  });

  $('body').click(function() {
    $('#user-nav').hide(); 
  });

  $('#user-nav').click(function(e){
    e.stopPropagation();
  });
});
4
Spencer Fry

Nakonec jsem udělal něco takového:

$(document).on('click', 'body, #msg_count_results .close',function() {
    $(document).find('#msg_count_results').remove();
});
$(document).on('click','#msg_count_results',function(e) {
    e.preventDefault();
    return false;
});

Mám zavřít tlačítko v novém kontejneru pro koncové uživatele přátelské UI účely. Musel jsem použít return false, abych neprošel. Samozřejmě, že mít HREF tam, aby vás někde by bylo pěkné, nebo byste mohli zavolat nějaké věci ajax místo toho. Ať tak či onak, funguje to dobře pro mě. To, co jsem chtěl.

4
Webmaster G

Realizovali jsme řešení, částečně založené na komentáři od výše uvedeného uživatele, který funguje perfektně pro nás. Používáme ho ke skrytí vyhledávacího pole/výsledků při kliknutí mimo tyto elementy, s výjimkou původního prvku.

// HIDE SEARCH BOX IF CLICKING OUTSIDE
$(document).click(function(event){ 
    // IF NOT CLICKING THE SEARCH BOX OR ITS CONTENTS OR SEARCH ICON 
    if ($("#search-holder").is(":visible") && !$(event.target).is("#search-holder *, #search")) {
        $("#search-holder").fadeOut('fast');
        $("#search").removeClass('active');
    }
});

Kontroluje, zda je vyhledávací pole již viditelné, a v našem případě také odstraní aktivní třídu na tlačítku hledání/zobrazení vyhledávání.

4

Řešení zde fungují dobře když má být spravován pouze jeden prvek . Pokud existuje více prvků, je problém mnohem složitější. Triky s e.stopPropagation () a všechny ostatní nebudou fungovat.

Přišel jsem s řešením a možná to není tak snadné, ale je to lepší než nic. Podívej se:

$view.on("click", function(e) {

    if(model.isActivated()) return;

        var watchUnclick = function() {
            rootView.one("mouseleave", function() {
                $(document).one("click", function() {
                    model.deactivate();
                });
                rootView.one("mouseenter", function() {
                    watchUnclick();
                });
            });
        };
        watchUnclick();
        model.activate();
    });
3
kboom

Zde je to, co mám dělat, abych problém vyřešil.

$(window).click(function (event) {
    //To improve performance add a checklike 
    //if(myElement.isClosed) return;
    var isClickedElementChildOfMyBox = isChildOfElement(event,'#id-of-my-element');

    if (isClickedElementChildOfMyBox)
        return;

    //your code to hide the element 
});

var isChildOfElement = function (event, selector) {
    if (event.originalEvent.path) {
        return event.originalEvent.path[0].closest(selector) !== null;
    }

    return event.originalEvent.originalTarget.closest(selector) !== null;
}
3
Fabian

Je-li někdo zvědavý, je to javascriptové řešení (es6):

window.addEventListener('mouseup', e => {
        if (e.target != yourDiv && e.target.parentNode != yourDiv) {
            yourDiv.classList.remove('show-menu');
            //or yourDiv.style.display = 'none';
        }
    })

a es5, jen v případě:

window.addEventListener('mouseup', function (e) {
if (e.target != yourDiv && e.target.parentNode != yourDiv) {
    yourDiv.classList.remove('show-menu'); 
    //or yourDiv.style.display = 'none';
}

});

3
Walt

Zde je jednoduché řešení čistým javascriptem. Je aktuální s ES6 :

var isMenuClick = false;
var menu = document.getElementById('menuscontainer');
document.addEventListener('click',()=>{
    if(!isMenuClick){
       //Hide the menu here
    }
    //Reset isMenuClick 
    isMenuClick = false;
})
menu.addEventListener('click',()=>{
    isMenuClick = true;
})
3
Duannx

To funguje pro mě

$("body").mouseup(function(e) {
    var subject = $(".main-menu");
    if(e.target.id != subject.attr('id') && !subject.has(e.target).length) {
        $('.sub-menu').hide();
    }
});
2
hienbt88
$(document).on("click",function (event)   
 {   
     console.log(event);
   if ($(event.target).closest('.element').length == 0)
     {
    //your code here
      if ($(".element").hasClass("active"))
      {
        $(".element").removeClass("active");
      }
     }
 });

Zkuste toto kódování pro získání řešení.

2

Zde je můj kód:

// Listen to every click
$('html').click(function(event) {
    if ( $('#mypopupmenu').is(':visible') ) {
        if (event.target.id != 'click_this_to_show_mypopupmenu') {
            $('#mypopupmenu').hide();
        }
    }
});

// Listen to selector's clicks
$('#click_this_to_show_mypopupmenu').click(function() {

  // If the menu is visible, and you clicked the selector again we need to hide
  if ( $('#mypopupmenu').is(':visible') {
      $('#mypopupmenu').hide();
      return true;
  }

  // Else we need to show the popup menu
  $('#mypopupmenu').show();
});
2
netdjw

Další řešení je zde:

http://jsfiddle.net/zR76D/

Používání:

<div onClick="$('#menu').toggle();$('#menu').clickOutside(function() { $(this).hide(); $(this).clickOutside('disable'); });">Open / Close Menu</div>
<div id="menu" style="display: none; border: 1px solid #000000; background: #660000;">I am a menu, whoa is me.</div>

Zapojit:

(function($) {
    var clickOutsideElements = [];
    var clickListener = false;

    $.fn.clickOutside = function(options, ignoreFirstClick) {
        var that = this;
        if (ignoreFirstClick == null) ignoreFirstClick = true;

        if (options != "disable") {
            for (var i in clickOutsideElements) {
                if (clickOutsideElements[i].element[0] == $(this)[0]) return this;
            }

            clickOutsideElements.Push({ element : this, clickDetected : ignoreFirstClick, fnc : (typeof(options) != "function") ? function() {} : options });

            $(this).on("click.clickOutside", function(event) {
                for (var i in clickOutsideElements) {
                    if (clickOutsideElements[i].element[0] == $(this)[0]) {
                        clickOutsideElements[i].clickDetected = true;
                    }
                }
            });

            if (!clickListener) {
                if (options != null && typeof(options) == "function") {
                    $('html').click(function() {
                        for (var i in clickOutsideElements) {
                            if (!clickOutsideElements[i].clickDetected) {
                                clickOutsideElements[i].fnc.call(that);
                            }
                            if (clickOutsideElements[i] != null) clickOutsideElements[i].clickDetected = false;
                        }
                    });
                    clickListener = true;
                }
            }
        }
        else {
            $(this).off("click.clickoutside");
            for (var i = 0; i < clickOutsideElements.length; ++i) {
                if (clickOutsideElements[i].element[0] == $(this)[0]) {
                    clickOutsideElements.splice(i, 1);
                }
            }
        }

        return this;
    }
})(jQuery);
2
teynon

Pokud používáte nástroje jako „Pop-up“, můžete použít událost „onFocusOut“.

window.onload=function(){
document.getElementById("inside-div").focus();
}
function loseFocus(){
alert("Clicked outside");
}
#container{
background-color:lightblue;
width:200px;
height:200px;
}

#inside-div{
background-color:lightgray;
width:100px;
height:100px;

}
<div id="container">
<input type="text" id="inside-div" onfocusout="loseFocus()">
</div>

2

Chci jen, aby @Pistos odpovídal, protože je ukrytý v komentářích.

Toto řešení fungovalo perfektně pro mě. Prostý JS:

var elementToToggle = $('.some-element');
$(document).click( function(event) {
  if( $(event.target).closest(elementToToggle).length === 0 ) {
    elementToToggle.hide();
  }
});

v jazyce CoffeeScript:

elementToToggle = $('.some-element')
$(document).click (event) ->
  if $(event.target).closest(elementToToggle).length == 0
    elementToToggle.hide()
2
DaniG2k

Čas to pro mě fungovalo naprosto v pořádku:

$('body').click(function() {
    // Hide the menus if visible.
});
2
govind

Vím, že na tuto otázku existuje milión odpovědí, ale vždy jsem byl fanouškem používání HTML a CSS pro většinu práce. V tomto případě z-index a umístění. Nejjednodušší způsob, jak jsem to zjistil, je následující:

$("#show-trigger").click(function(){
  $("#element").animate({width: 'toggle'});
  $("#outside-element").show();
});
$("#outside-element").click(function(){
  $("#element").hide();
  $("#outside-element").hide();
});
#outside-element {
  position:fixed;
  width:100%;
  height:100%;
  z-index:1;
  display:none;
}
#element {
  display:none;
  padding:20px;
  background-color:#ccc;
  width:300px;
  z-index:2;
  position:relative;
}
#show-trigger {
  padding:20px;
  background-color:#ccc;
  margin:20px auto;
  z-index:2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="outside-element"></div>
<div id="element">
  <div class="menu-item"><a href="#1">Menu Item 1</a></div>
  <div class="menu-item"><a href="#2">Menu Item 1</a></div>
  <div class="menu-item"><a href="#3">Menu Item 1</a></div>
  <div class="menu-item"><a href="#4">Menu Item 1</a></div>
</div>
<div id="show-trigger">Show Menu</div>

To vytváří bezpečné prostředí, protože se nic nezačne spouštět, pokud není nabídka skutečně otevřená a index z chrání některý obsah uvnitř prvku před vytvořením chybného zapalování po klepnutí.

Kromě toho nemusíte vyžadovat, aby jQuery pokrýval všechny vaše základny propagačními hovory a musel očistit všechny vnitřní prvky od zapalování.

2
Lucas

Odpověď označená jako přijatá odpověď nebere v úvahu, že můžete mít překrytí nad prvkem, jako jsou dialogy, popovers, datepickers, atd. Kliknutí v nich by neměla skrýt prvek.

Udělal jsem vlastní verzi, která to bere v úvahu. Je vytvořen jako vazba KnockoutJS vázání, ale může být snadno převedena do formátu jQuery-only.

Pracuje podle prvního dotazu pro všechny elementy, které jsou viditelné z-indexu nebo absolutní polohy. To pak hit testy těchto prvků proti prvku chci skrýt, pokud kliknete mimo. Pokud je to hit, vypočítám nový vázaný obdélník, který bere v úvahu hranice překrytí.

ko.bindingHandlers.clickedIn = (function () {
    function getBounds(element) {
        var pos = element.offset();
        return {
            x: pos.left,
            x2: pos.left + element.outerWidth(),
            y: pos.top,
            y2: pos.top + element.outerHeight()
        };
    }

    function hitTest(o, l) {
        function getOffset(o) {
            for (var r = { l: o.offsetLeft, t: o.offsetTop, r: o.offsetWidth, b: o.offsetHeight };
                o = o.offsetParent; r.l += o.offsetLeft, r.t += o.offsetTop);
            return r.r += r.l, r.b += r.t, r;
        }

        for (var b, s, r = [], a = getOffset(o), j = isNaN(l.length), i = (j ? l = [l] : l).length; i;
            b = getOffset(l[--i]), (a.l == b.l || (a.l > b.l ? a.l <= b.r : b.l <= a.r))
                && (a.t == b.t || (a.t > b.t ? a.t <= b.b : b.t <= a.b)) && (r[r.length] = l[i]));
        return j ? !!r.length : r;
    }

    return {
        init: function (element, valueAccessor) {
            var target = valueAccessor();
            $(document).click(function (e) {
                if (element._clickedInElementShowing === false && target()) {
                    var $element = $(element);
                    var bounds = getBounds($element);

                    var possibleOverlays = $("[style*=z-index],[style*=absolute]").not(":hidden");
                    $.each(possibleOverlays, function () {
                        if (hitTest(element, this)) {
                            var b = getBounds($(this));
                            bounds.x = Math.min(bounds.x, b.x);
                            bounds.x2 = Math.max(bounds.x2, b.x2);
                            bounds.y = Math.min(bounds.y, b.y);
                            bounds.y2 = Math.max(bounds.y2, b.y2);
                        }
                    });

                    if (e.clientX < bounds.x || e.clientX > bounds.x2 ||
                        e.clientY < bounds.y || e.clientY > bounds.y2) {

                        target(false);
                    }
                }
                element._clickedInElementShowing = false;
            });

            $(element).click(function (e) {
                e.stopPropagation();
            });
        },
        update: function (element, valueAccessor) {
            var showing = ko.utils.unwrapObservable(valueAccessor());
            if (showing) {
                element._clickedInElementShowing = true;
            }
        }
    };
})();
2
Anders

Abych byl upřímný, žádné z předchozích řešení se mi nelíbilo.

Nejlepším způsobem, jak toho dosáhnout, je vazba události „click“ na dokument a porovnání, zda je toto kliknutí opravdu mimo prvek (stejně jako v jeho návrhu řekl Art).

Nicméně, budete mít nějaké problémy tam: Nikdy nebudete moci odpojení, a nemůžete mít externí tlačítko otevřít/zavřít tento prvek.

To je důvod, proč jsem napsal tento malý plugin (klikněte zde pro odkaz) , zjednodušit tyto úkoly. Mohlo by to být jednodušší?

<a id='theButton' href="#">Toggle the menu</a><br/>
<div id='theMenu'>
    I should be toggled when the above menu is clicked,
    and hidden when user clicks outside.
</div>

<script>
$('#theButton').click(function(){
    $('#theMenu').slideDown();
});
$("#theMenu").dClickOutside({ ignoreList: $("#theButton") }, function(clickedObj){
    $(this).slideUp();
});
</script>
2
Alexandre T.

Nejširší způsob, jak toho dosáhnout, je vybrat vše na webové stránce s výjimkou elementu, kde nechcete, aby byla zjištěna kliknutí, a svázat událost s klepnutím, když je nabídka otevřena. 

Po zavření nabídky zrušte vazbu.

Pomocí příkazu .stopPropagation zabráníte tomu, aby událost ovlivnila jakoukoliv část konzoly menu.

$("*").not($("#menuscontainer")).bind("click.OutsideMenus", function ()
{
    // hide the menus

    //then remove all of the handlers
    $("*").unbind(".OutsideMenus");
});

$("#menuscontainer").bind("click.OutsideMenus", function (event) 
{
    event.stopPropagation(); 
});
2
maday
jQuery().ready(function(){
    $('#nav').click(function (event) {
        $(this).addClass('activ');
        event.stopPropagation();
    });

    $('html').click(function () {
        if( $('#nav').hasClass('activ') ){
            $('#nav').removeClass('activ');
        }
    });
});
2
Toogy

U dotykových zařízení, jako je iPad a iPhone, můžeme tento kód použít:

$(document).on('touchstart', function (event) {
    var container = $("YOUR CONTAINER SELECTOR");

    if (!container.is(e.target) &&            // If the target of the click isn't the container...
        container.has(e.target).length === 0) // ... nor a descendant of the container
    {
        container.hide();
    }
});
2

Pro některé lidi to může být lepší oprava. 

$(".menu_link").click(function(){
    // show menu code
});

$(".menu_link").mouseleave(function(){
    //hide menu code, you may add a timer for 3 seconds before code to be run
});

Vím, že mouseleave neznamená pouze kliknout mimo, ale také znamená opustit tuto oblast.

Jakmile je samotné menu umístěno v prvku menu_link, pak by samotné menu nemělo být problémem kliknout nebo pokračovat.

1
Waheed
$('#propertyType').on("click",function(e){
          self.propertyTypeDialog = !self.propertyTypeDialog;
          b = true;
          e.stopPropagation();
          console.log("input clicked");
      });

      $(document).on('click','body:not(#propertyType)',function (e) {
          e.stopPropagation();
          if(b == true)  {
              if ($(e.target).closest("#configuration").length == 0) {
                  b = false;
                  self.propertyTypeDialog = false;
                  console.log("outside clicked");
              }
          }
        // console.log($(e.target).closest("#configuration").length);
      });
1
chea sotheara

Věřím, že nejlepší způsob, jak to udělat, je něco takového. 

$(document).on("click", function(event) {
  clickedtarget = $(event.target).closest('#menuscontainer');
  $("#menuscontainer").not(clickedtarget).hide();
});

Tento typ řešení by mohl být snadno vytvořen pro práci s více nabídkami a také nabídkami, které jsou dynamicky přidávány pomocí JavaScriptu. V podstatě vám to umožňuje kliknout kdekoli v dokumentu a zkontrolovat, na který prvek jste klikli, a vybere jej nejbližší "#menuscontainer". Pak skryje všechny menu, ale vyloučí ten, na který jste klikli. 

Nejste si jisti, jak přesně jsou vaše menu postavena, ale neváhejte a zkopírujte můj kód do JSFiddle. Je to velmi jednoduchý, ale důkladně funkční menu/modální systém. Vše, co musíte udělat, je vytvořit html-menu a kód bude dělat práci za vás.

https://jsfiddle.net/zs6anrn7/

1
Waltur Buerk

Chcete-li skrýt fileTreeClass pokud na něj kliknete mimo něj 

 jQuery(document).mouseup(function (e) {
            var container = $(".fileTreeClass");
            if (!container.is(e.target) // if the target of the click isn't the container...
                && container.has(e.target).length === 0) // ... nor a descendant of the container
            {
                container.hide();
            }
        });
1
Thamaraiselvam

Jednoduchý plugin:

$.fn.clickOff = function(callback, selfDestroy) {
    var clicked = false;
    var parent = this;
    var destroy = selfDestroy || true;

    parent.click(function() {
        clicked = true;
    });

    $(document).click(function(event) {
        if (!clicked && parent.is(':visible')) {
            if(callback) callback.call(parent, event)
        }
        if (destroy) {
            //parent.clickOff = function() {};
            //parent.off("click");
            //$(document).off("click");
            parent.off("clickOff");
        }
        clicked = false;
    });
};

Použití:

$("#myDiv").clickOff(function() {
   alert('clickOff');
});
1
froilanq

pokud chcete zobrazit okno, když kliknete na tlačítko a podržíte toto okno, když kliknete mimo.

document.body.onclick = function() { undisp_menu(); };
var menu_on = 0;

function menu_trigger(event){

    if (menu_on == 0)
    {
        // otherwise u will call the undisp on body when 
        // click on the button
        event.stopPropagation(); 

        disp_menu();
    }

    else{
        undisp_menu();
    }

}


function disp_menu(){

    menu_on = 1;
    var e = document.getElementsByClassName("menu")[0];
    e.className = "menu on";

}

function undisp_menu(){

    menu_on = 0;
    var e = document.getElementsByClassName("menu")[0];
    e.className = "menu";

}

nezapomeňte na toto tlačítko

<div class="button" onclick="menu_trigger(event)">

<div class="menu">

a css:

.menu{
    display: none;
}

.on {
    display: inline-block;
}
0
Aominé

Zkuste si to vyzkoušet:

$('html').click(function(e) {
  if($(e.target).parents('#menuscontainer').length == 0) {
    $('#menuscontainer').hide();
  }
});

https://jsfiddle.net/4cj4jxy0/

Všimněte si však, že to nemůže fungovat, pokud událost click nemůže dosáhnout značky html. (Možná, že další prvky mají stopPropagation()).

0
Yishu Fang

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

$('#menucontainer').click(function(event){
    event.stopPropagation();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
 <button id='#menucontainer'>Ok</button> 
</html>

0
Autumnswind

Odebírat zachytávat fázi kliknout zvládnout klikněte na prvky, které volají preventDefault.
Načtete jej na element dokumentu pomocí jiného názvu click-anywhere.

document.addEventListener('click', function (event) {
  event = $.event.fix(event);
  event.type = 'click-anywhere';
  $document.trigger(event);
}, true);

Pak, kde budete potřebovat funkci mimo kliknutí, přihlaste se k události click-anywhere v document a zkontrolujte, zda bylo kliknutí mimo prvek, který vás zajímá:

$(document).on('click-anywhere', function (event) {
  if (!$(event.target).closest('#smth').length) {
    // Do anything you need here
  }
});

Některé poznámky:

  • Musíte použít document, protože by to byla chyba v chování, která by spustila událost na všech prvcích, mimo které došlo k kliknutí.

  • Tato funkce může být zabalena do speciálního pluginu, který volá nějaké zpětné volání na vnější kliknutí.

  • Fáze zachycení nemůžete přihlásit pomocí jQuery samotného.

  • Nepotřebujete načtení dokumentu, chcete-li se přihlásit k odběru, protože předplatné je na document, dokonce i na jeho body, takže existuje vždy nezávisle na umístění skriptu a stavu načítání.

0
Qwertiy

Řekněme, že div, který chcete detekovat, pokud uživatel klikl mimo nebo uvnitř, má id, například: "my-special-widget".

Poslouchejte události kliknutí na tělo:

document.body.addEventListener('click', (e) => {
    if (isInsideMySpecialWidget(e.target, "my-special-widget")) {
        console.log("user clicked INSIDE the widget");
    }
    console.log("user clicked OUTSIDE the widget");
});

function isInsideMySpecialWidget(elem, mySpecialWidgetId){
    while (elem.parentElement) {
        if (elem.id === mySpecialWidgetId) {
            return true;
        }
        elem = elem.parentElement;
    }
    return false;
}

V tomto případě neporušíte normální tok kliknutí na některý prvek ve vaší stránce, protože nepoužíváte metodu "stopPropagation".

0
Yair Cohen
$(document).on('click.menu.hide', function(e){
  if ( !$(e.target).closest('#my_menu').length ) {
    $('#my_menu').find('ul').toggleClass('active', false);
  }
});

$(document).on('click.menu.show', '#my_menu li', function(e){
  $(this).find('ul').toggleClass('active');
});
div {
  float: left;
}

ul {
  padding: 0;
  position: relative;
}
ul li {
  padding: 5px 25px 5px 10px;
  border: 1px solid silver;
  cursor: pointer;
  list-style: none;
  margin-top: -1px;
  white-space: nowrap;
}
ul li ul:before {
  margin-right: -20px;
  position: absolute;
  top: -17px;
  right: 0;
  content: "\25BC";
}
ul li ul li {
  visibility: hidden;
  height: 0;
  padding-top: 0;
  padding-bottom: 0;
  border-width: 0 0 1px 0;
}
ul li ul li:last-child {
  border: none;
}
ul li ul.active:before {
  content: "\25B2";
}
ul li ul.active li {
  display: list-item;
  visibility: visible;
  height: inherit;
  padding: 5px 25px 5px 10px;
}
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<div>
  <ul id="my_menu">
    <li>Menu 1
      <ul>
        <li>subMenu 1</li>
        <li>subMenu 2</li>
        <li>subMenu 3</li>
        <li>subMenu 4</li>
      </ul>
    </li>
    <li>Menu 2
      <ul>
        <li>subMenu 1</li>
        <li>subMenu 2</li>
        <li>subMenu 3</li>
        <li>subMenu 4</li>
      </ul>
    </li>
    <li>Menu 3</li>
    <li>Menu 4</li>
    <li>Menu 5</li>
    <li>Menu 6</li>
  </ul>
</div>

Zde je verze jsbin http://jsbin.com/xopacadeni/edit?html,css,js,output

0
FDisk
    $('#menucontainer').click(function(e){
        e.stopPropagation();
     });

    $(document).on('click',  function(e){
        // code
    });
0
Nitekurs

Když kliknete na/vypnete prvek, přepnete menu Nav. 

$(document).on('click', function(e) {
    var elem = $(e.target).closest('#menu'),
    box = $(e.target).closest('#nav');
 if (elem.length) {
    e.preventDefault();
    $('#nav').toggle();
  } else if (!box.length) {
    $('#nav').hide();
 }
});



<li id="menu"><a></a></li>
<ul id="nav" >  //Nav will toggle when you Click on Menu(it can be an icon in this example)
        <li class="page"><a>Page1</a></li>
        <li class="page"><a>Pag2</a></li>
        <li class="page"><a>Page3</a></li>            
        <li class="page"><a>Page4</a></li>
</ul>
0
Awena

Toto je obecnější řešení, které umožňuje sledování více prvků a dynamické přidávání a odstraňování prvků z fronty.

Obsahuje globální frontu (autoCloseQueue) - kontejner objektu pro prvky, které by měly být uzavřeny na vnějších kliknutích. 

Každý klíč objektu fronty by měl být ID prvku DOM a hodnota by měla být objekt s 2 funkcemi zpětného volání: 

 {onPress: someCallbackFunction, onOutsidePress: anotherCallbackFunction}

Dejte to zpět do zpětného volání připraveného k dokumentu:

window.autoCloseQueue = {}  

$(document).click(function(event) {
    for (id in autoCloseQueue){
        var element = autoCloseQueue[id];
        if ( ($(e.target).parents('#' + id).length) > 0) { // This is a click on the element (or its child element)
            console.log('This is a click on an element (or its child element) with  id: ' + id);
            if (typeof element.onPress == 'function') element.onPress(event, id);
        } else { //This is a click outside the element
            console.log('This is a click outside the element with id: ' + id);
            if (typeof element.onOutsidePress == 'function') element.onOutsidePress(event, id); //call the outside callback
            delete autoCloseQueue[id]; //remove the element from the queue
        }
    }
});

Když je potom vytvořen prvek DOM s ID 'menuscontainer', přidejte tento objekt do fronty: 

window.autoCloseQueue['menuscontainer'] = {onOutsidePress: clickOutsideThisElement}
0
Roei Bahumi