it-swarm.com.de

Wie erkenne ich einen Klick außerhalb eines Elements?

Ich habe einige HTML-Menüs, die vollständig angezeigt werden, wenn ein Benutzer auf den Kopf dieser Menüs klickt. Ich möchte diese Elemente ausblenden, wenn der Benutzer außerhalb des Menübereichs klickt.

Ist so etwas mit jQuery möglich?

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

HINWEIS: Die Verwendung von stopEventPropagation() sollte vermieden werden, da der normale Ereignisfluss im DOM unterbrochen wird. In diesem Artikel finden Sie weitere Informationen. Verwenden Sie stattdessen diese Methode

Hängen Sie ein Klickereignis an den Dokumenthauptteil an, der das Fenster schließt. Fügen Sie dem Container ein separates Klickereignis hinzu, das die Weitergabe an den Dokumenthauptteil stoppt.

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

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

Sie können ein click - Ereignis auf document abhören und dann sicherstellen, dass #menucontainer kein Vorfahr oder Ziel des angeklickten Elements ist, indem Sie .closest() verwenden.

Ist dies nicht der Fall, befindet sich das angeklickte Element außerhalb von #menucontainer und Sie können es sicher ausblenden.

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

Bearbeiten - 2017-06-23

Sie können auch nach dem Ereignis-Listener bereinigen, wenn Sie das Menü schließen und die Überwachung von Ereignissen beenden möchten. Diese Funktion bereinigt nur den neu erstellten Listener, wobei alle anderen Klicklistener auf document erhalten bleiben. Mit ES2015-Syntax:

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

Bearbeiten - 2018-03-11

Für diejenigen, die jQuery nicht verwenden möchten. Hier ist der obige Code in plain 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 

HINWEIS: Dies basiert auf dem Kommentar von Alex, der anstelle des jQuery-Teils nur !element.contains(event.target) verwendet.

Aber element.closest() ist jetzt auch in allen gängigen Browsern verfügbar (die W3C-Version unterscheidet sich ein wenig von jQuery) . Polyfills finden Sie hier: https://developer.mozilla.org/en-US/docs/ Web/API/Element/am nächsten

1228
Art

Wie erkenne ich einen Klick außerhalb eines Elements?

Der Grund, warum diese Frage so beliebt ist und so viele Antworten hat, ist, dass sie täuschend komplex ist. Nach fast acht Jahren und Dutzenden von Antworten bin ich wirklich überrascht zu sehen, wie wenig Wert auf Barrierefreiheit gelegt wurde.

Ich möchte diese Elemente ausblenden, wenn der Benutzer außerhalb des Menübereichs klickt.

Dies ist eine edle Sache und das eigentliche Problem. Der Titel der Frage - was die meisten Antworten zu beantworten scheinen - enthält einen unglücklichen roten Hering.

Hinweis: Es ist das Wort "Klick" !

Sie möchten eigentlich keine Click-Handler binden.

Wenn Sie Click-Handler binden, um das Dialogfeld zu schließen, ist dies bereits fehlgeschlagen. Der Grund, warum Sie gescheitert sind, ist, dass nicht jeder click-Ereignisse auslöst. Benutzer, die keine Maus verwenden, können Ihren Dialog durch Drücken von verlassen (und Ihr Popup-Menü ist möglicherweise eine Art Dialog) Tabund sie können dann den Inhalt hinter dem Dialogfeld nicht lesen, ohne anschließend ein Ereignis clickauszulösen.

Also lasst uns die Frage umformulieren.

Wie schließt man einen Dialog, wenn ein Benutzer damit fertig ist?

Das ist das Ziel. Leider müssen wir jetzt das Ereignis userisfinishedwiththedialogbinden, und diese Bindung ist nicht so einfach.

Wie können wir also feststellen, dass ein Benutzer die Verwendung eines Dialogfelds beendet hat?

focusoutevent

Ein guter Anfang ist festzustellen, ob der Fokus den Dialog verlassen hat.

Hinweis: Seien Sie vorsichtig mit dem Ereignis blurname__, blurverbreitet sich nicht, wenn das Ereignis an die Bubbling-Phase gebunden war!

jQueries focusoutNAME _ reicht völlig aus. Wenn Sie jQuery nicht verwenden können, können Sie während der Erfassungsphase blurverwenden:

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

Außerdem müssen Sie in vielen Dialogen zulassen, dass der Container den Fokus erhält. Fügen Sie tabindex="-1" hinzu, damit der Dialog dynamisch den Fokus erhält, ohne den Tabulatorfluss zu unterbrechen.

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

Wenn Sie länger als eine Minute mit dieser Demo spielen, sollten Sie schnell anfangen, Probleme zu erkennen.

Der erste ist, dass der Link im Dialogfeld nicht anklickbar ist. Wenn Sie versuchen, darauf oder auf einen Tab zu klicken, wird der Dialog geschlossen, bevor die Interaktion stattfindet. Dies liegt daran, dass durch das Fokussieren des inneren Elements ein Ereignis focusoutausgelöst wird, bevor erneut ein Ereignis focusinausgelöst wird.

Der Fix besteht darin, die Statusänderung in der Ereignisschleife in die Warteschlange zu stellen. Dies kann mit setImmediate(...) oder setTimeout(..., 0) für Browser erfolgen, die setImmediatenicht unterstützen. Einmal in die Warteschlange gestellt, kann es durch einen nachfolgenden focusinabgebrochen werden:

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

Das zweite Problem ist, dass der Dialog nicht geschlossen wird, wenn der Link erneut gedrückt wird. Dies liegt daran, dass das Dialogfeld den Fokus verliert und das Schließen auslöst. Danach wird das Dialogfeld durch Klicken auf den Link erneut geöffnet.

Ähnlich wie in der vorherigen Ausgabe muss der Fokusstatus verwaltet werden. Da die Statusänderung bereits in die Warteschlange gestellt wurde, müssen lediglich Fokusereignisse für die Dialogauslöser behandelt werden:

Dies sollte vertraut aussehen
$('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 Schlüssel

Wenn Sie der Meinung sind, dass Sie mit den Fokuszuständen fertig sind, können Sie noch mehr tun, um die Benutzererfahrung zu vereinfachen.

Dies ist oft eine "Nice to have" -Funktion, aber es ist üblich, dass wenn Sie eine modale oder Popup-Funktion haben, die die Esc Taste schließt es aus.

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>

Wenn Sie wissen, dass Sie fokussierbare Elemente im Dialogfeld haben, müssen Sie das Dialogfeld nicht direkt fokussieren. Wenn Sie ein Menü erstellen, können Sie stattdessen das erste Menüelement fokussieren.

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-Rollen und andere Unterstützung für Barrierefreiheit

Diese Antwort behandelt hoffentlich die Grundlagen der Unterstützung von Tastaturen und Mäusen für diese Funktion, aber da sie bereits ziemlich umfangreich ist, werde ich jede Diskussion über WAI-ARIA-Rollen und -Attribute vermeiden, jedoch ich Ich rate den Implementierern dringend , in der Spezifikation nachzulesen, welche Rollen sie verwenden sollen und welche anderen geeigneten Attribute sie verwenden sollen.

248
zzzzBov

Die anderen Lösungen hier funktionierten nicht für mich, daher musste ich Folgendes verwenden:

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

Ich habe eine Anwendung, die ähnlich funktioniert wie Erans Beispiel, mit der Ausnahme, dass ich das Klickereignis an den Körper anhefte, wenn ich das Menü öffne ...

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

  event.stopPropagation();
});

Weitere Informationen zur Funktion one() von jQuery

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

Funktioniert gut für mich.

36
user212621

Nun gibt es ein Plugin für das: außerhalb von Ereignissen ( blog post )

Folgendes geschieht, wenn ein clickoutside - Handler (WLOG) an ein Element gebunden ist:

  • das Element wird zu einem Array hinzugefügt, das alle Elemente mit clickoutside - Handlern enthält
  • a ( namespaced ) click handler is bound to the document (if not already there)
  • bei jedem click im Dokument wird das Ereignis clickoutside für diejenigen Elemente in diesem Array ausgelöst, die nicht dem übergeordneten Ziel des click -events entsprechen
  • das event.target für das clickoutside -Ereignis wird außerdem auf das Element gesetzt, auf das der Benutzer geklickt hat (damit Sie sogar wissen, was der Benutzer angeklickt hat, und nicht nur, dass er außerhalb geklickt hat).

Es werden also keine Ereignisse von der Weitergabe angehalten und zusätzliche click - Handler können "über" dem Element mit dem externen Handler verwendet werden.

35
Wolfram

Nach Recherchen habe ich drei funktionierende Lösungen gefunden (ich habe die Seitenlinks als Referenz vergessen)

Erste Lösung

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

Zweite Lösung

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

Dritte Lösung

<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

Das hat für mich perfekt funktioniert !!

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

Ich glaube nicht, dass Sie wirklich das Menü schließen müssen, wenn der Benutzer nach draußen klickt. Sie müssen das Menü schließen, wenn der Benutzer irgendwo auf die Seite klickt. Wenn Sie auf das Menü klicken oder das Menü verlassen, sollte es richtig geschlossen werden. 

Nachdem ich keine befriedigenden Antworten gefunden hatte, wurde ich neulich aufgefordert, diesen Blogpost zu schreiben. Für die mehr Pedikanten gibt es eine Reihe von gotchas zu beachten: 

  1. Wenn Sie zum Zeitpunkt des Anklickens einen click-Ereignishandler an das body-Element anhängen, warten Sie auf den 2. Klick, bevor Sie das Menü schließen und das Ereignis aufheben. Andernfalls wird das Klickereignis, das das Menü geöffnet hat, zu dem Listener geleitet, der das Menü schließen muss.
  2. Wenn Sie event.stopPropogation () für ein Klickereignis verwenden, können keine anderen Elemente auf Ihrer Seite eine Funktion zum Klicken auf eine beliebige Stelle zum Schließen haben.
  3. Das unbegrenzte Anhängen eines Click-Ereignishandlers an das body-Element ist keine performante Lösung
  4. Wenn Sie das Ziel des Ereignisses und dessen Eltern mit dem Ersteller des Handlers vergleichen, wird davon ausgegangen, dass Sie beim Schließen des Menüs das Menü schließen möchten. Wenn Sie das Ereignis jedoch wirklich schließen möchten, klicken Sie auf eine beliebige Stelle der Seite.
  5. Wenn Sie auf Ereignisse im body-Element hören, wird der Code spröder. Ein so unschuldiges Styling würde dies zerstören: body { margin-left:auto; margin-right: auto; width:960px;}
24
34m0

Wie bereits in einem anderen Poster erwähnt, gibt es viele Gotchas, insbesondere wenn das Element, das Sie anzeigen (in diesem Fall ein Menü), interaktive Elemente enthält .. Ich habe die folgende Methode als ziemlich robust empfunden:

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

Eine einfache Lösung für die Situation ist:

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

Das obige Skript blendet die Variable div aus, wenn außerhalb des Klickereignisses div ausgelöst wird.

Weitere Informationen finden Sie im folgenden Blog: http://www.codecanal.com/detect-click-outside-div-using-javascript/

20
Jitendra Damor

Lösung1

Anstatt event.stopPropagation () zu verwenden, das einige Nebeneffekte haben kann, definieren Sie einfach eine einfache Flagvariable und fügen Sie eine if-Bedingung hinzu. Ich habe das getestet und funktionierte ohne Nebenwirkungen von 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";
    }
});

Lösung2

Mit nur einer einfachen if-Bedingung:

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

Überprüfen Sie das Fenster-Klickereignisziel (es sollte sich an das Fenster ausbreiten, sofern es nicht an anderer Stelle erfasst wird), und stellen Sie sicher, dass es keines der Menüelemente ist. Wenn dies nicht der Fall ist, befinden Sie sich außerhalb Ihres Menüs.

Oder überprüfen Sie die Position des Klicks und prüfen Sie, ob er im Menübereich enthalten ist.

18
Chris MacDonald

Ich hatte Erfolg mit so etwas:

var $menuscontainer = ...;

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

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

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

Die Logik lautet: Wenn #menuscontainer angezeigt wird, binden Sie einen Klick-Handler an den Körper, der #menuscontainer nur verbirgt, wenn das Ziel (des Klicks) nicht untergeordnet ist.

15
Chu Yeow

Als Variante:

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

Es gibt kein Problem mit Stoppen der Ereignisausbreitung und unterstützt besser mehrere Menüs auf derselben Seite, in denen ein Klick auf ein zweites Menü, während ein erstes geöffnet ist, das erste in der stopPropagation-Lösung geöffnet lässt.

14
Bohdan Lyzanets

Ich habe diese Methode in einem jQuery-Kalender-Plugin gefunden.

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

Das Ereignis hat eine Eigenschaft mit dem Namen event.path des Elements, bei der es sich um eine statisch geordnete "Liste aller Vorfahren in Baumreihenfolge" handelt. Um zu prüfen, ob ein Ereignis von einem bestimmten DOM-Element oder einem seiner untergeordneten Elemente stammt, prüfen Sie einfach den Pfad für dieses bestimmte DOM-Element. Es kann auch verwendet werden, um mehrere Elemente durch logische ORing der Elementprüfung in der some-Funktion zu überprüfen.

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

Also für Ihren Fall sollte es sein 

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

Hier ist die Vanilla JavaScript-Lösung für zukünftige Zuschauer.

Wenn Sie auf ein Element im Dokument klicken und die ID des angeklickten Elements umschaltet oder das ausgeblendete Element nicht ausgeblendet wird und das ausgeblendete Element das angeklickte Element nicht enthält, schalten Sie das Element um.

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

Wenn Sie mehrere Schalter auf derselben Seite verwenden möchten, können Sie Folgendes verwenden:

  1. Fügen Sie dem reduzierbaren Element den Klassennamen hidden hinzu.
  2. Schließen Sie beim Klicken auf das Dokument alle ausgeblendeten Elemente, die das angeklickte Element nicht enthalten und nicht ausgeblendet sind
  3. Wenn das angeklickte Element ein Umschalter ist, können Sie das angegebene Element umschalten.

(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

Verwenden Sie stattdessen Flussunterbrechung, Unschärfe/Fokus-Ereignis oder andere knifflige Techniken. Passen Sie den Ereignisfluss einfach an die Verwandtschaft von element an:

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

So entfernen Sie den Click-Listener für Ereignisse:

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

Wenn Sie Skripts für IE und FF 3. * erstellen und nur wissen möchten, ob der Klick in einem bestimmten Boxbereich aufgetreten ist, könnten Sie auch Folgendes verwenden:

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

Benutzen:

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

Ich bin überrascht, dass niemand das focusout-Ereignis bestätigt hat:

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

Haken Sie einen Klickereignislistener in das Dokument ein. Im Ereignislistener können Sie das event object betrachten, insbesondere das event.target , um zu sehen, auf welches Element geklickt wurde:

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

Wenn Sie auf das Dokument klicken, blenden Sie ein bestimmtes Element aus, sofern Sie nicht auf dasselbe Element klicken.

5
Rowan

Für eine einfachere Verwendung und ausdrucksstärkeren Code habe ich dafür ein jQuery-Plugin erstellt:

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

Hinweis: target ist das Element, auf das der Benutzer tatsächlich geklickt hat. Callback wird jedoch weiterhin im Kontext des ursprünglichen Elements ausgeführt, sodass Sie this wie in einem jQuery-Callback erwartet verwenden können.

Plugin:

$.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;
};

Standardmäßig wird der Klickereignislistener im Dokument platziert. Wenn Sie jedoch den Gültigkeitsbereich des Ereignis-Listeners einschränken möchten, können Sie ein jQuery-Objekt übergeben, das ein übergeordnetes Element darstellt, das das oberste übergeordnete Element ist, bei dem Klicks angehört werden. Dies verhindert unnötige Listener auf Ereignisebene. Offensichtlich funktioniert es nur, wenn das übergeordnete Element ein übergeordnetes Element Ihres ursprünglichen Elements ist. 

Verwenden Sie wie folgt:

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

Ich habe es so gemacht in 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();
    }
});

Ich überprüfe, ob der Vorgänger nicht der Widget-Element-Container ist. 
Wenn das Ziel nicht das Widget/Element öffnet, 
Wenn das Widget/Element, das ich schließen möchte, bereits geöffnet ist (nicht so wichtig).

5
Satya Prakash

Die beliebteste Antwort wurde positiv bewertet, aber fügen Sie hinzu 

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

wenn Sie also auf eine Bildlaufleiste klicken, wird Ihr Zielelement nicht ausgeblendet.

5
bbe

Das sollte funktionieren:

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

Funktion:

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

Verwendungszweck:

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

Und Funktionen sind sehr einfach:

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

Ich habe unten Skript benutzt und mit jQuery gemacht.

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

Unten finden Sie den HTML-Code

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

Sie können das Tutorial hier lesen. 

4
Rinto George

Dies ist meine Lösung für dieses Problem:

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

Am Ende habe ich so etwas gemacht:

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

Ich habe eine Schaltfläche zum Schließen in dem neuen Container für Endbenutzer-freundliche Benutzeroberflächen. Ich musste return false verwenden, um nicht durchzugehen. Natürlich wäre es schön, einen A HREF dort hinzubringen, um Sie dorthin zu bringen, oder Sie könnten stattdessen Ajax-Sachen nennen. So oder so funktioniert es für mich in Ordnung. Genau das, was ich wollte.

4
Webmaster G

Wir haben eine Lösung implementiert, die teilweise auf einem Kommentar eines Benutzers basiert und für uns perfekt funktioniert. Wir verwenden es, um ein Suchfeld/Ergebnisse auszublenden, wenn Sie außerhalb dieser Elemente klicken, mit Ausnahme des ursprünglichen Elements.

// 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');
    }
});

Es prüft, ob das Suchfeld auch zuerst sichtbar ist. In unserem Fall entfernt es auch eine aktive Klasse über die Schaltfläche zum Ein-/Ausblenden der Suche.

4

Die Lösungen hier funktionieren gut wenn nur ein Element verwaltet werden soll . Wenn es mehrere Elemente gibt, ist das Problem jedoch viel komplizierter. Tricks mit e.stopPropagation () und allen anderen funktionieren nicht.

Ich habe mir eine Lösung ausgedacht , und vielleicht ist es nicht so einfach, aber es ist besser als nichts. Guck mal:

$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

Hier ist was ich mache um das Problem zu lösen.

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

Wenn jemand neugierig ist, ist hier Javascript-Lösung (es6):

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

und es5, nur für den Fall:

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

Hier ist eine einfache Lösung von reinem Javascript. Es ist aktuell mit 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

Das funktioniert für mich

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

Versuchen Sie diese Kodierung, um die Lösung zu erhalten.

2

Hier ist mein Code:

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

Eine weitere Lösung ist hier:

http://jsfiddle.net/zR76D/

Verwendungszweck:

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

Plugin:

(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

Wenn Sie Werkzeuge wie "Popup" verwenden, können Sie das Ereignis "onFocusOut" verwenden.

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

Ich möchte nur die Antwort von @Pistos deutlicher machen, da sie in den Kommentaren verborgen ist.

Diese Lösung hat für mich perfekt funktioniert. Einfacher JS:

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

in CoffeeScript:

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

Das hat für mich perfekt funktioniert:

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

Ich weiß, dass es eine Million Antworten auf diese Frage gibt, aber ich war schon immer ein Fan von HTML und CSS, um die meiste Arbeit zu erledigen. In diesem Fall Z-Index und Positionierung. Der einfachste Weg, den ich dazu gefunden habe, ist folgender:

$("#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>

Dies schafft eine sichere Umgebung, da nichts ausgelöst wird, es sei denn, das Menü ist tatsächlich geöffnet, und der Z-Index schützt den Inhalt des Elements vor dem Aussondern, wenn beim Klicken ein Fehler auftritt.

Außerdem benötigen Sie nicht jQuery, um alle Ihre Basen mit Ausbreitungsaufrufen abzudecken und alle inneren Elemente von Aussetzern zu entfernen.

2
Lucas

Bei der als akzeptierte Antwort markierten Antwort wird nicht berücksichtigt, dass das Element überlagert werden kann, z. B. Dialoge, Popovers, Datumsauswahl usw. Durch Klicken auf diese Elemente sollte das Element nicht ausgeblendet werden.

Ich habe meine eigene Version erstellt, die dies berücksichtigt. Es wurde als KnockoutJS - Bindung erstellt, kann jedoch leicht in jQuery-only konvertiert werden.

Bei der ersten Abfrage wird für alle sichtbaren Elemente mit Z-Index oder absoluter Position gearbeitet. Anschließend werden diese Elemente mit dem Element verglichen, das ich ausblenden möchte, wenn Sie mit der Außenseite klicken. Wenn es ein Treffer ist, berechne ich ein neues gebundenes Rechteck, das die Überlagerungsgrenzen berücksichtigt.

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

Um ehrlich zu sein, ich mochte keine der bisherigen Lösungen.

Der beste Weg, dies zu tun, besteht darin, das Ereignis "click" an das Dokument zu binden und zu vergleichen, ob sich dieser Klick wirklich außerhalb des Elements befindet (genau wie Art in seinem Vorschlag sagte).

Allerdings gibt es dort einige Probleme: Sie können sie niemals lösen, und Sie können keine externe Taste zum Öffnen/Schließen des Elements haben.

Deshalb habe ich dieses kleine Plugin (hier klicken, um einen Link) zu schreiben , um diese Aufgaben zu vereinfachen. Könnte es einfacher sein?

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

Die umfassendste Möglichkeit, dies zu tun, besteht darin, alles auf der Webseite auszuwählen, mit Ausnahme des Elements, bei dem keine Klicks erkannt werden sollen, und das Klickereignis an das Binden des Menüs gebunden, wenn das Menü geöffnet wird. 

Wenn das Menü geschlossen ist, entfernen Sie die Bindung.

Verwenden Sie die Option .stopPropagation, um zu verhindern, dass das Ereignis einen Teil des Menücontainers beeinflusst.

$("*").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

Für Touch-Geräte wie iPad und iPhone können wir diesen Code verwenden:

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

Dies könnte für manche Leute eine bessere Lösung sein. 

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

Ich weiß, dass Mauseleave nicht nur einen Klick nach außen bedeutet, sondern auch, dass der Bereich dieses Elements verlassen wird.

Wenn sich das Menü selbst innerhalb des menu_link-Elements befindet, sollte das Menü selbst kein Problem sein, wenn Sie darauf klicken oder fortfahren.

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

Ich glaube, der beste Weg ist so etwas. 

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

Diese Art von Lösung lässt sich leicht für mehrere Menüs sowie für Menüs, die dynamisch über Javascript hinzugefügt werden, herstellen. Im Grunde erlaubt es Ihnen einfach, irgendwo in Ihr Dokument zu klicken und zu überprüfen, welches Element Sie angeklickt haben, und wählt das nächste "#menuscontainer" aus. Dann werden alle Menücontainer ausgeblendet, derjenige jedoch ausgeschlossen, in den Sie geklickt haben. 

Ich bin nicht sicher, wie Ihre Menüs genau aufgebaut sind, aber Sie können meinen Code in JSFiddle kopieren. Es ist ein sehr einfaches, aber durch und durch funktionelles Menü-/Modalsystem. Sie müssen lediglich die HTML-Menüs erstellen und der Code erledigt die Arbeit für Sie.

https://jsfiddle.net/zs6anrn7/

1
Waltur Buerk

fileTreeClass ausblenden, wenn außerhalb geklickt wird 

 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

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

Benutzen:

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

wenn Sie nur ein Fenster anzeigen möchten, wenn Sie auf eine Schaltfläche klicken, und das Fenster nicht anzeigen, wenn Sie auf die Schaltfläche "Außen" klicken (oder erneut auf die Schaltfläche), klappt dies

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

}

vergiss das nicht für den Button

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

<div class="menu">

und die css:

.menu{
    display: none;
}

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

Probieren Sie es aus:

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

https://jsfiddle.net/4cj4jxy0/

Beachten Sie jedoch, dass dies nicht funktionieren kann, wenn das Ereignis click das Tag html nicht erreichen kann. (Vielleicht haben andere Elemente stopPropagation()).

0
Yishu Fang

Nur eine Warnung, dass dies verwendet:

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

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

Es verhindert der Ruby on Rails UJS-Treiber funktioniert nicht ordnungsgemäß. Beispielsweise funktioniert link_to 'click', '/url', :method => :delete nicht.

Dies kann eine Problemumgehung sein:

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

$('#menucontainer').click(function(event){
  if (!$(event.target).data('method')) {
    event.stopPropagation();
  }
});
0
mlangenberg

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

Abonnieren Sie Capturing-Phase von click, um auf Elemente zu klicken, die preventDefault aufrufen.
Leiten Sie es erneut für ein Dokumentelement mit dem anderen Namen click-anywhere aus.

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

Wenn Sie dann außerhalb des click-anywhere-Ereignisses auf document einen Klick für die Funktionalität außerhalb des Bereichs benötigen, prüfen Sie, ob der Klick außerhalb des gewünschten Elements war:

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

Einige Notizen:

  • Sie müssen document verwenden, da dies ein Leistungsfehler sein würde, um event auf alle Elemente auszulösen, außerhalb derer der Klick stattgefunden hat.

  • Diese Funktionalität kann in ein spezielles Plugin eingebunden werden, das bei einem externen Klick einen Rückruf aufruft.

  • Sie können die Erfassungsphase nicht mit jQuery selbst abonnieren.

  • Sie benötigen kein Dokument zum Abonnieren, da das Abonnement sich auf document befindet, auch nicht auf dessen body. Es ist also immer unabhängig von der Skriptplatzierung und dem Ladestatus vorhanden.

0
Qwertiy

Nehmen wir an, das Div, das Sie ermitteln möchten, wenn der Benutzer außerhalb oder innen geklickt hat, hat eine ID, zum Beispiel: "mein Spezial-Widget".

Hören Sie sich Body-Click-Ereignisse an:

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

In diesem Fall wird der normale Klickfluss auf ein Element auf Ihrer Seite nicht unterbrochen, da Sie die Methode "stopPropagation" nicht verwenden.

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>

Hier ist die Version von 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

Dadurch wird das Nav-Menü umgeschaltet, wenn Sie auf das Element klicken. 

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

Dies ist eine allgemeinere Lösung, mit der mehrere Elemente überwacht werden können und Elemente dynamisch aus der Warteschlange hinzugefügt und daraus entfernt werden können .

Es enthält eine globale Warteschlange ( autoCloseQueue ) - einen Objektcontainer für Elemente, die bei Klicks von außen geschlossen werden sollen. 

Jeder Warteschlangenobjektschlüssel sollte die DOM-Element-ID sein und der Wert sollte ein Objekt mit zwei Rückruffunktionen sein: 

 {onPress: someCallbackFunction, onOutsidePress: anotherCallbackFunction}

Fügen Sie dies in Ihren Callback-Dokument ein:

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

Wenn das DOM-Element mit der ID ' Menuscontainer ' erstellt wird, fügen Sie einfach dieses Objekt der Warteschlange hinzu: 

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