javascript - when - react js click outside component




Wie erkenne ich einen Klick außerhalb eines Elements? (20)

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

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

Hängen Sie ein Klickereignis an den Dokumenthauptteil an, der das Fenster schließt. Hängen Sie ein separates Klickereignis an den Container an, der die Weitergabe an den Dokumenthauptteil beendet.

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

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

Wie erkennt man einen Klick außerhalb eines Elements?

Der Grund, dass 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, wie wenig Aufmerksamkeit auf die Zugänglichkeit 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 sein scheinen - enthält einen unglücklichen roten Hering.

Hinweis: es ist das Wort "Klick" !

Sie möchten eigentlich keine Klick-Handler binden.

Wenn Sie binden, klicken Sie auf Handler, um das Dialogfeld zu schließen. Sie sind bereits fehlgeschlagen. Der Grund, warum Sie versagt haben, ist, dass nicht jeder Klickereignisse auslöst. Benutzer, die keine Maus verwenden, können den Dialog durch Drücken der Tabulatortaste (und das Popup-Menü ist wahrscheinlich eine Art Dialog) verlassen. Sie können dann den Inhalt des Dialogs nicht lesen, ohne anschließend einen click auszulösen Veranstaltung.

Lassen Sie uns die Frage neu formulieren.

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

Das ist das Ziel. Leider müssen wir jetzt den userisfinishedwiththedialog dem userisfinishedwiththedialog , und diese Bindung ist nicht so einfach.

Wie können wir also feststellen, dass ein Benutzer einen Dialog beendet hat?

focusout Ereignis

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

Hinweis: Seien Sie vorsichtig mit dem blur , blur sich nicht, wenn das Ereignis an die Sprudelphase gebunden war!

Der focusout jQuery wird gut funktionieren. Wenn Sie jQuery nicht verwenden können, können Sie während der Aufnahmephase blur :

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

Bei vielen Dialogen müssen Sie außerdem den Fokus des Containers erhalten. Fügen Sie tabindex="-1" , damit der Dialog den Fokus dynamisch empfangen kann, ohne dass sonst der Tabulatorfluss unterbrochen wird.

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

Der erste ist, dass der Link im Dialogfeld nicht anklickbar ist. Wenn Sie versuchen, auf die Registerkarte oder die Registerkarte zu klicken, wird der Dialog geschlossen, bevor die Interaktion stattfindet. Dies liegt daran, dass das Fokussieren des inneren Elements ein focusout Ereignis auslöst, bevor erneut ein focusin Event focusin wird.

Das Update besteht darin, die Statusänderung in der Ereignisschleife in die Warteschlange zu stellen. Dies kann mithilfe von setImmediate(...) oder setTimeout(..., 0) für Browser ausgeführt werden, die setImmediate nicht unterstützen. Einmal in die Warteschlange gestellt, kann es durch einen nachfolgenden focusin abgebrochen 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 das Dialogfeld nicht geschlossen wird, wenn der Link erneut gedrückt wird. Dies liegt daran, dass der Dialog den Fokus verliert und das Schließen-Verhalten auslöst, wonach der Link-Klick den Dialog zum erneuten Öffnen auslöst.

Ähnlich wie in der vorherigen Ausgabe muss der Fokusstatus verwaltet werden. Da sich der Statuswechsel bereits in der Warteschlange befindet, müssen Sie nur die Fokusereignisse auf den Dialogauslösern behandeln:

Das sollte bekannt 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- Taste

Wenn Sie der Meinung waren, Sie wären mit der Behandlung der Fokuszustände fertig, können Sie noch mehr tun, um die Benutzererfahrung zu vereinfachen.

Dies ist oft eine "schöne" Funktion, aber es ist üblich, dass die Esc- Taste, wenn Sie über ein modales oder ein Popup-Fenster verfügen, dieses schließt.

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 sich im Dialog fokussierbare Elemente befinden, müssen Sie den Dialog nicht direkt fokussieren. Wenn Sie ein Menü erstellen, können Sie stattdessen den ersten Menüpunkt 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 Eingabehilfen

Diese Antwort deckt hoffentlich die Grundlagen der Tastatur- und Mausunterstützung für dieses Feature ab. Da dies jedoch bereits recht groß ist, werde ich jede Diskussion über die Rollen und Attribute von WAI-ARIA vermeiden. Ich empfehle jedoch dringend , dass Implementierer auf die Spezifikation für Details Bezug nehmen welche Rollen sie verwenden sollen und welche anderen geeigneten Attribute.


Überprüfen Sie das Fenster-Klickereignisziel (es sollte sich auf 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.


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 hat kein Problem mit dem css-tricks.com/dangers-stopping-event-propagation 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.


Das hat für mich perfekt funktioniert !!

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

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

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

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

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

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 den Klassennamen hiddenzum reduzierbaren Element 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>


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

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


Jetzt gibt es ein Plugin dafür: Outside Events ( Blogpost )

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
  • ein ( namespaced ) Click- Handler ist an das Dokument gebunden (falls nicht bereits vorhanden)
  • Bei jedem Klick im Dokument wird das Clickoutside- Ereignis für die Elemente in diesem Array ausgelöst, die nicht dem übergeordneten Ziel des Click- Event-Objekts entsprechen
  • Darüber hinaus ist das event.target für das clickoutside- Ereignis auf das Element festgelegt, auf das der Benutzer geklickt hat (damit Sie sogar wissen, was der Benutzer angeklickt hat, nicht nur, dass er außerhalb geklickt hat)

Daher werden keine Ereignisse von der Weitergabe angehalten und zusätzliche Klick- Handler können "über" dem Element mit dem Outside-Handler verwendet werden.


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>

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

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

    })
});

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 innerhalb des neuen Containers 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 zu haben, der Sie dorthin bringt, oder Sie könnten stattdessen Ajax-Sachen nennen. So oder so funktioniert es für mich in Ordnung. Genau das, was ich wollte


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

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: Ziel ist das Element, auf das der Benutzer tatsächlich geklickt hat. Callback wird jedoch immer noch im Kontext des ursprünglichen Elements ausgeführt, sodass Sie dies 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 überwacht 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...
});

Wenn Sie für IE und FF 3. * Skripts erstellen und nur wissen möchten, ob der Klick in einem bestimmten Boxbereich stattgefunden hat, 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;}

Das Ereignis hat eine Eigenschaft namens 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 zur Überprüfung mehrerer Elemente verwendet werden, indem ORdie Elementprüfung in der someFunktion logisch durchgeführt wird .

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

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.


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

Funktioniert gut für mich.







jquery