usare - visualizzare immagine javascript




Come posso rilevare un clic all'esterno di un elemento? (20)

Come rilevare un clic all'esterno di un elemento?

La ragione per cui questa domanda è così popolare e ha così tante risposte è che è ingannevolmente complessa. Dopo quasi otto anni e dozzine di risposte, sono sinceramente sorpreso di vedere quanto poca attenzione sia stata data all'accessibilità.

Vorrei nascondere questi elementi quando l'utente fa clic all'esterno dell'area dei menu.

Questa è una nobile causa ed è il vero problema. Il titolo della domanda, che è ciò che la maggior parte delle risposte sembra tentare di affrontare, contiene una sfortunata falsa pista.

Suggerimento: è la parola "clic" !

In realtà non vuoi associare gestori di clic.

Se stai vincolando i gestori di clic per chiudere la finestra di dialogo, hai già fallito. Il motivo per cui hai fallito è che non tutti attivano gli eventi click . Gli utenti che non usano il mouse saranno in grado di sfuggire alla finestra di dialogo (e il menu a comparsa è probabilmente un tipo di finestra di dialogo) premendo Tab e quindi non saranno in grado di leggere il contenuto dietro la finestra di dialogo senza successivamente attivare un click evento.

Quindi riformuliamo la domanda.

Come si chiude una finestra di dialogo quando un utente ha finito con esso?

Questo è l'obiettivo Sfortunatamente, ora abbiamo bisogno di associare l' userisfinishedwiththedialog evento userisfinishedwiththedialog e userisfinishedwiththedialog non è così semplice.

Quindi, come possiamo rilevare che un utente ha finito di usare una finestra di dialogo?

evento di messa a focusout

Un buon inizio è determinare se la messa a fuoco ha lasciato la finestra di dialogo.

Suggerimento: fai attenzione con l'evento blur , la blur non si propaga se l'evento è stato associato alla fase di bubbling!

Il focusout di jQuery andrà benissimo. Se non puoi usare jQuery, puoi usare la blur durante la fase di acquisizione:

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

Inoltre, per molte finestre di dialogo è necessario consentire al contenitore di concentrarsi. Aggiungi tabindex="-1" per consentire al dialogo di ricevere il focus in modo dinamico senza interrompere in altro modo il flusso di tabulazione.

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

Se giochi con quella demo per più di un minuto dovresti iniziare subito a vedere i problemi.

Il primo è che il link nella finestra di dialogo non è selezionabile. Tentando di fare clic su di esso o sulla scheda, si aprirà la finestra di dialogo prima che avvenga l'interazione. Questo perché la messa a fuoco dell'elemento interno innesca un evento di focusout a focusout prima di attivare nuovamente un evento di focusin .

La correzione è di accodare la modifica dello stato sul ciclo degli eventi. Questo può essere fatto usando setImmediate(...) , o setTimeout(..., 0) per i browser che non supportano setImmediate . Una volta accodato, può essere annullato da un successivo focusin :

$('.submenu').on({
  focusout: function (e) {
    $(this).data('submenuTimer', setTimeout(function () {
      $(this).removeClass('submenu--active');
    }.bind(this), 0));
  },
  focusin: function (e) {
    clearTimeout($(this).data('submenuTimer'));
  }
});

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

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

Il secondo problema è che la finestra di dialogo non si chiude quando il link viene premuto di nuovo. Questo perché la finestra di dialogo perde lo stato attivo, attivando il comportamento di chiusura, dopo di che il clic del collegamento attiva la finestra di dialogo per riaprire.

Simile al problema precedente, lo stato di messa a fuoco deve essere gestito. Dato che la modifica dello stato è già stata accodata, è solo questione di gestire gli eventi di attivazione sui trigger di dialogo:

Questo dovrebbe sembrare familiare
$('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>

Tasto Esc

Se pensavi di aver finito gestendo gli stati di attivazione, puoi fare di più per semplificare l'esperienza dell'utente.

Questa è spesso una funzionalità "bella da avere", ma è comune che quando si ha una modale o una finestra popup di qualsiasi tipo, il tasto Esc la chiuderà.

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>

Se sai di avere elementi attivabili nella finestra di dialogo, non dovrai mettere a fuoco direttamente la finestra di dialogo. Se stai creando un menu, puoi invece concentrare la prima voce del menu.

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

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

$('.submenu').on({
  focusout: function () {
    $(this).data('submenuTimer', setTimeout(function () {
      $(this).removeClass('submenu--active');
    }.bind(this), 0));
  },
  focusin: function () {
    clearTimeout($(this).data('submenuTimer'));
  },
  keydown: function (e) {
    if (e.which === 27) {
      $(this).removeClass('submenu--active');
      e.preventDefault();
    }
  }
});
.menu {
  list-style: none;
  margin: 0;
  padding: 0;
}
.menu:after {
  clear: both;
  content: '';
  display: table;
}
.menu__item {
  float: left;
  position: relative;
}

.menu__link {
  background-color: lightblue;
  color: black;
  display: block;
  padding: 0.5em 1em;
  text-decoration: none;
}
.menu__link:hover,
.menu__link:focus {
  background-color: black;
  color: lightblue;
}

.submenu {
  border: 1px solid black;
  display: none;
  left: 0;
  list-style: none;
  margin: 0;
  padding: 0;
  position: absolute;
  top: 100%;
}
.submenu--active {
  display: block;
}

.submenu__item {
  width: 150px;
}

.submenu__link {
  background-color: lightblue;
  color: black;
  display: block;
  padding: 0.5em 1em;
  text-decoration: none;
}

.submenu__link:hover,
.submenu__link:focus {
  background-color: black;
  color: lightblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="menu">
  <li class="menu__item">
    <a class="menu__link" href="#menu-1">Menu 1</a>
    <ul class="submenu" id="menu-1" tabindex="-1">
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li>
    </ul>
  </li>
  <li class="menu__item">
    <a  class="menu__link" href="#menu-2">Menu 2</a>
    <ul class="submenu" id="menu-2" tabindex="-1">
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#1">Example 1</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#2">Example 2</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#3">Example 3</a></li>
      <li class="submenu__item"><a class="submenu__link" href="http://example.com/#4">Example 4</a></li>
    </ul>
  </li>
</ul>
lorem ipsum <a href="http://example.com/">dolor</a> sit amet.

Ruoli di WAI-ARIA e altro supporto di accessibilità

Questa risposta si spera copra le basi del supporto accessibile per tastiera e mouse per questa funzionalità, ma poiché è già abbastanza considerevole eviterò qualsiasi discussione sui ruoli e gli attributi WAI-ARIA , tuttavia raccomando fortemente che gli implementatori facciano riferimento alle specifiche per i dettagli su quali ruoli dovrebbero utilizzare e altri attributi appropriati.

Ho alcuni menu HTML, che mostro completamente quando un utente fa clic sulla testa di questi menu. Vorrei nascondere questi elementi quando l'utente fa clic all'esterno dell'area dei menu.

È qualcosa di simile a questo possibile con jQuery?

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

NOTA: l'uso di stopEventPropagation() è qualcosa che dovrebbe essere evitato poiché interrompe il normale flusso di eventi nel DOM. Vedi questo articolo per ulteriori informazioni. Prendi in considerazione l'utilizzo di questo metodo .

Allegare un evento click al corpo del documento che chiude la finestra. Allegare un evento click separato al contenitore che interrompe la propagazione al corpo del documento.

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

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

Come un altro poster ha detto che ci sono molti trucchi, specialmente se l'elemento che stai visualizzando (in questo caso un menu) ha elementi interattivi. Ho trovato il seguente metodo per essere abbastanza robusto:

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

    })
});

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

Non ha alcun problema con l' css-tricks.com/dangers-stopping-event-propagation e il migliore supporto di più menu sulla stessa pagina in cui il clic su un secondo menu mentre un primo è aperto lascerà il primo aperto nella soluzione stopPropagation.


Dopo la ricerca ho trovato tre soluzioni funzionanti (ho dimenticato i collegamenti alle pagine per riferimento)

Prima soluzione

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

Seconda soluzione

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

Terza soluzione

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

Ecco la soluzione JavaScript di vaniglia per i futuri spettatori.

Facendo clic su qualsiasi elemento all'interno del documento, se l'id dell'elemento su cui si fa clic è attivato, o l'elemento nascosto non è nascosto e l'elemento nascosto non contiene l'elemento cliccato, attiva l'elemento.

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

Se hai intenzione di avere più commutatori sulla stessa pagina puoi usare qualcosa come questo:

  1. Aggiungi il nome della classe hidden all'elemento comprimibile.
  2. Al clic del documento, chiudi tutti gli elementi nascosti che non contengono l'elemento cliccato e non sono nascosti
  3. Se l'elemento cliccato è un interruttore, attiva l'elemento specificato.

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


Ho avuto successo con qualcosa del genere:

var $menuscontainer = ...;

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

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

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

La logica è: quando viene visualizzato #menuscontainer , associare un gestore di clic al corpo che nasconde #menuscontainer solo se il target (del clic) non è figlio di esso.


Ho finito per fare qualcosa del genere:

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

Ho un pulsante di chiusura all'interno del nuovo contenitore per scopi di interfaccia utente amichevole degli utenti finali. Ho dovuto usare return false per non passare. Certo, avere un A HREF lì per portarti da qualche parte sarebbe bello, oppure potresti chiamare qualche roba ajax. Ad ogni modo, funziona bene per me. Proprio quello che volevo.


Ho un'applicazione che funziona in modo simile all'esempio di Eran, tranne che allego l'evento click al corpo quando apro il menu ... Un po 'come questo:

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

  event.stopPropagation();
});

Maggiori informazioni sulla funzione one() di jQuery


Le altre soluzioni qui non hanno funzionato per me quindi ho dovuto usare:

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

Ora c'è un plugin per questo: eventi esterni ( post sul blog )

Quanto segue accade quando un gestore di clickoutside (WLOG) è associato a un elemento:

  • l'elemento viene aggiunto a un array che contiene tutti gli elementi con gestori clickoutside
  • un gestore di clic (con lo namespaced ) è associato al documento (se non già presente)
  • su qualsiasi clic nel documento, l'evento clickoutside viene attivato per quegli elementi in quell'array che non sono uguali o un genitore del target click -events
  • inoltre, event.target per l'evento clickoutside è impostato sull'elemento su cui l'utente ha fatto clic (in modo da sapere anche cosa l'utente ha fatto clic, non solo che ha fatto clic all'esterno)

Quindi nessun evento viene interrotto dalla propagazione e ulteriori gestori di clic possono essere utilizzati "sopra" l'elemento con il gestore esterno.


Puoi ascoltare un evento click sul document e assicurarti che #menucontainer non sia un antenato o la destinazione dell'elemento cliccato usando .closest() .

Se non lo è, allora l'elemento cliccato è al di fuori del #menucontainer e puoi tranquillamente nasconderlo.

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

Modifica - 2017-06-23

Puoi anche ripulire dopo il listener di eventi se prevedi di chiudere il menu e vuoi smettere di ascoltare gli eventi. Questa funzione pulirà solo il listener appena creato, preservando qualsiasi altro click lister sul document . Con la sintassi ES2015:

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

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

  document.addEventListener('click', outsideClickListener)
}

Modifica - 2018-03-11

Per coloro che non vogliono usare jQuery. Ecco il codice sopra in plain vanillaJS (ECMAScript6).

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

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

    document.addEventListener('click', outsideClickListener)
}

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

NOTA: questo è basato sul commento di Alex per usare semplicemente !element.contains(event.target) invece della parte jQuery.

Ma element.closest() è ora disponibile anche in tutti i principali browser (la versione W3C differisce un po 'da quella di jQuery). Polyfills può essere trovato qui: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest


Una soluzione semplice per la situazione è:

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

Lo script sopra nasconderà il div se viene attivato l'evento di clic div al di fuori dell'evento div .

Puoi vedere il seguente blog per maggiori informazioni: http://www.codecanal.com/detect-click-outside-div-using-javascript/


Uso:

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

Per un utilizzo più semplice e un codice più espressivo, ho creato un plug-in jQuery per questo:

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

Nota: target è l'elemento in cui l'utente ha effettivamente fatto clic. Ma callback viene ancora eseguito nel contesto dell'elemento originale, in modo da poter utilizzare questo come ci si aspetterebbe in un callback jQuery.

Collegare:

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

Per impostazione predefinita, il listener dell'evento click viene inserito nel documento. Tuttavia, se si desidera limitare l'ambito del listener di eventi, è possibile passare un oggetto jQuery che rappresenta un elemento di livello superiore che sarà il principale a cui verranno ascoltati i clic. Questo impedisce inutili listener di eventi a livello di documento. Ovviamente, non funzionerà a meno che l'elemento genitore fornito non sia un genitore del tuo elemento iniziale.

Utilizzare in questo modo:

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

Questa è la mia soluzione a questo problema:

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

Upvote per la risposta più popolare, ma aggiungi

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

quindi, un clic su una barra di scorrimento non [nasconde o altro] il tuo elemento di destinazione.


Abbiamo implementato una soluzione, in parte basata su un commento di un utente sopra, che funziona perfettamente per noi. Lo utilizziamo per nascondere una casella di ricerca / risultati quando fai clic all'esterno di tali elementi, escludendo l'elemento che originariamente.

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

Controlla anche se la casella di ricerca è già visibile per prima, e nel nostro caso rimuove anche una classe attiva nel pulsante di ricerca nascondi / mostra.


L'evento ha una proprietà chiamata event.path dell'elemento che è un "elenco ordinato statico di tutti i suoi antenati nell'ordine dell'albero" . Per verificare se un evento è stato originato da uno specifico elemento DOM o da uno dei suoi figli, basta controllare il percorso per quello specifico elemento DOM. Può anche essere usato per controllare più elementi effettuando logicamente ORil controllo degli elementi nella somefunzione.

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

Quindi per il tuo caso dovrebbe essere

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

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

Funziona per me bene.







jquery