javascript - tag - w3schools html reference pdf




كيف يمكنني اكتشاف نقرة خارج عنصر ما؟ (20)

كيفية اكتشاف النقرة خارج عنصر ما؟

السبب في أن هذا السؤال شائع جدًا ولديه العديد من الإجابات هو أنه معقد بشكل خادع. بعد ما يقرب من ثماني سنوات وعشرات الإجابات ، فوجئت حقًا برؤية مدى الحرص القليل الذي تم منحه لإمكانية الوصول.

أود إخفاء هذه العناصر عندما ينقر المستخدم خارج منطقة القوائم.

هذه قضية نبيلة وهي القضية الفعلية . يحتوي عنوان السؤال - وهو ما يبدو أن معظم الأجوبة تحاول معالجته - على رنجة حمراء مؤسفة.

تلميح: إنها كلمة "فوق" !

أنت لا تريد في الواقع ربط معالجات النقر.

إذا كنت معالجا للنقر ملزمة لإغلاق مربع الحوار ، فهذا يعني أنك أخفقت بالفعل. السبب الذي أخفقتَه هو أنه لا يُشغَّل جميع الأشخاص الأحداث. سيتمكن المستخدمون الذين لا يستخدمون الماوس من الهروب من مربع الحوار (والقائمة المنبثقة هي نوع من أنواع الحوار) عن طريق الضغط على مفتاح الجدولة (Tab) ، ولن يتمكنوا بعد ذلك من قراءة المحتوى خلف مربع الحوار دون أن يؤدي ذلك إلى click هدف.

لذا دعنا نعيد صياغة السؤال.

كيف يغلق أحدهم الحوار عند الانتهاء من المستخدم؟

هذا هو الهدف. لسوء الحظ ، نحتاج الآن إلى ربط الحدث الذي userisfinishedwiththedialog ، وهذا الربط ليس واضحًا تمامًا.

إذن كيف يمكننا اكتشاف انتهاء المستخدم من استخدام مربع حوار؟

حدث focusout

البداية الجيدة هي تحديد ما إذا كان التركيز قد ترك الحوار.

تلميح: كن حذراً مع حدث blur ، لا ينتشر blur إذا كان الحدث مرتبطًا بمرحلة الفقاعة!

سيكون focusout في jQuery على ما يرام. إذا كنت لا تستطيع استخدام jQuery ، فيمكنك استخدام blur خلال مرحلة الالتقاط:

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

أيضًا ، بالنسبة إلى العديد من مربعات الحوار ، ستحتاج إلى السماح للحاوية بالتركيز. أضف tabindex="-1" للسماح لمربع الحوار بتلقي التركيز بشكل ديناميكي دون مقاطعة تدفق الجدولة.

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

إذا كنت تلعب بهذا العرض التوضيحي لأكثر من دقيقة ، فعليك البدء بسرعة في رؤية المشكلات.

الأول هو أن الرابط الموجود في مربع الحوار غير قابل للنقر. ستؤدي محاولة النقر عليه أو علامة التبويب إليه إلى إغلاق الحوار قبل حدوث التفاعل. ويرجع ذلك إلى أن تركيز العنصر الداخلي يؤدي إلى focusout حدث focusout قبل focusout حدث focusout مرة أخرى.

الإصلاح هو قائمة انتظار تغيير الحالة في حلقة الحدث. يمكن القيام بذلك باستخدام setImmediate(...) أو setTimeout(..., 0) للمتصفحات التي لا تدعم setImmediate . وبمجرد وضعه في قائمة الانتظار ، يمكن إلغاؤه 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>

المشكلة الثانية هي أن مربع الحوار لن يغلق عند الضغط على الرابط مرة أخرى. ويرجع ذلك إلى أن مربع الحوار يفقد التركيز ، مما يؤدي إلى سلوك الإغلاق ، وبعد ذلك يؤدي النقر على الرابط إلى إعادة فتح مربع الحوار لإعادة فتحه.

على غرار الإصدار السابق ، يجب إدارة حالة التركيز. وبالنظر إلى أن تغيير الحالة قد تم وضعه في قائمة الانتظار بالفعل ، فإن الأمر يتعلق فقط بمعالجة أحداث التركيز على مشغلات الحوار:

هذا يجب أن تبدو مألوفة
$('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

إذا كنت تعتقد أنك انتهيت من خلال التعامل مع حالات التركيز ، فهناك المزيد الذي يمكنك القيام به لتبسيط تجربة المستخدم.

غالبًا ما تكون هذه الميزة "من الجيد أن يكون لديك" ، ولكن من الشائع أنه عندما يكون لديك نموذج أو منبثق من أي نوع ، فإن مفتاح Esc سيغلقه .

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>

إذا كنت تعرف أن لديك عناصر قابلة للتركيز في مربع الحوار ، فلن تحتاج إلى تركيز مربع الحوار مباشرة. إذا كنت تنشئ قائمة ، فيمكنك التركيز على عنصر القائمة الأول بدلاً من ذلك.

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 ودعم إمكانية الوصول الأخرى

وتغطي هذه الإجابة على أمل أساسيات دعم لوحة المفاتيح والماوس التي يمكن الوصول إليها لهذه الميزة ، ولكن بما أنها كبيرة بالفعل ، فسوف أتجنب أي مناقشة لأدوار وخصائص WAI-ARIA ، ومع ذلك أوصي بشدة بأن يقوم المنفذون بالرجوع إلى المواصفات للحصول على التفاصيل. حول الأدوار التي يجب استخدامها وأي سمات مناسبة أخرى.

لدي بعض قوائم HTML ، والتي أعرضها تمامًا عندما ينقر المستخدم على رأس هذه القوائم. أود إخفاء هذه العناصر عندما ينقر المستخدم خارج منطقة القوائم.

هل مثل هذا ممكن مع jQuery؟

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

ملاحظة: استخدام stopEventPropagation() أمر يجب تجنبه لأنه يكسر تدفق الأحداث العادي في DOM. انظر هذه المقالة لمزيد من المعلومات. فكر في استخدام هذه الطريقة بدلاً من ذلك.

إرفاق حدث نقرة بهيئة المستند التي تغلق النافذة. أرفق حدثًا نقرًا منفصلاً بالحاوية التي توقف انتشارها في نص المستند.

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

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

استعمال:

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

الحل البسيط للحالة هو:

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

سيخفي النص أعلاه عملية div إذا كان يتم تشغيل الحدث خارج نقرة div .

يمكنك الاطلاع على المدونة التالية لمزيد من المعلومات: http://www.codecanal.com/detect-click-outside-div-using-javascript/


تحقق من هدف حدث نقر النافذة (يجب أن ينتشر إلى النافذة ، طالما أنه لم يتم تسجيله في أي مكان آخر) ، وتأكد من عدم وجود أي عنصر من عناصر القائمة. إذا لم يكن كذلك ، فأنت خارج القائمة الخاصة بك.

أو تحقق من موضع النقرة ، وتحقق مما إذا كان موجودًا داخل منطقة القائمة.


كصيغة:

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

ليس لديها مشكلة مع css-tricks.com/dangers-stopping-event-propagation وتدعم بشكل أفضل قوائم متعددة في نفس الصفحة حيث سيؤدي النقر فوق قائمة ثانية بينما يفتح الأول إلى ترك أول جلسة مفتوحة في حل stopPropagation.


لا أعتقد أن ما تحتاجه فعليًا هو إغلاق القائمة عندما ينقر المستخدم في الخارج ؛ ما تحتاجه هو أن تغلق القائمة عندما ينقر المستخدم في أي مكان على الصفحة. إذا قمت بالنقر فوق القائمة ، أو إيقاف القائمة ، يجب إغلاق؟

دفعني العثور على إجابات مرضية أعلاه إلى كتابة هذا التدوينة في اليوم الآخر. لمزيد من pedantic ، هناك عدد من gotchas أن نلاحظ ما يلي:

  1. إذا أرفقت معالج حدث النقر بعنصر النص الأساسي في وقت النقرة ، فاحرص على الانتظار للنقرة الثانية قبل إغلاق القائمة وإلغاء ربط الحدث. وإلا ، فإن الفقاعة التفسيرية التي تفتح القائمة ستظهر على قائمة المستمعين لإغلاق القائمة.
  2. إذا كنت تستخدم event.stopPropogation () في حدث نقرة ، فلن تحتوي أي عناصر أخرى في صفحتك على ميزة click-to-close.
  3. إن إرفاق معالج حدث النقر بعنصر الجسد إلى أجل غير مسمى ليس حلاً ناجحاً
  4. مقارنة هدف الحدث ، ويفترض أولياء الأمور إلى منشئ المعالج أن ما تريده هو إغلاق القائمة عند النقر عليها ، عندما تكون ما تريده حقًا هو إغلاقه عند النقر في أي مكان على الصفحة.
  5. الاستماع للأحداث على عنصر الجسم سيجعل كودك أكثر هشاشة. التصميم بريء لأن هذا من شأنه أن يكسره: body { margin-left:auto; margin-right: auto; width:960px;} body { margin-left:auto; margin-right: auto; width:960px;}

لدي تطبيق يعمل بشكل مشابه لمثال عيران ، إلا أنني أرفق حدث النقر بالجسم عندما أفتح القائمة ... Kinda like this: Kinda like this:

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

  event.stopPropagation();
});

مزيد من المعلومات عن وظيفة one() jQuery ل


لقد وجدت هذه الطريقة في بعض المكوّنات الإضافية jQuery calendar.

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

لم تنجح الحلول الأخرى هنا لذا اضطررت لاستخدام:

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

وظيفة:

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

الاستعمال:

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

والوظائف بسيطة للغاية:

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

يمكنك الاستماع لحدث النقر على document ثم التأكد من أن #menucontainer ليس سلفًا أو هدف العنصر الذي تم النقر عليه باستخدام .closest() .

إذا لم يكن الأمر كذلك ، فسيكون العنصر الذي تم النقر عليه خارج #menucontainer ويمكنك إخفاءه بأمان.

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

تعديل - 2017-06-23

يمكنك أيضا تنظيف بعد مستمع الحدث إذا كنت تخطط لإسقاط القائمة وتريد التوقف عن الاستماع للأحداث. ستقوم هذه الوظيفة بتنظيف المستمع الذي تم إنشاؤه حديثًا ، مع الحفاظ على أي مستمعين آخرين للنقر على document . باستخدام بنية 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)
}

تحرير - 2018-03-11

بالنسبة لأولئك الذين لا يرغبون في استخدام jQuery. وهنا الرمز أعلاه في سهل 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 

ملاحظة: هذا يعتمد على تعليق Alex ليستخدم فقط !element.contains(event.target) بدلاً من جزء jQuery.

ولكن element.closest() متوفر الآن في جميع المتصفحات الرئيسية (يختلف إصدار W3C قليلاً عن jQuery one). يمكن العثور على موقع Polyfills هنا: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest


إذا كنت تقوم بالبرمجة النصية لـ IE و FF 3. * وترغب فقط في معرفة ما إذا كانت النقرة قد حدثت داخل منطقة معينة ، يمكنك أيضًا استخدام ما يلي:

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

التصويت على الإجابة الأكثر شيوعًا ، ولكن أضفها

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

لذلك ، لا تؤدي أي نقرة على شريط التمرير إلى إخفاء العنصر المطلوب.


فبدلاً من استخدام انقطاع التدفق أو حدث الضبابية / التركيز أو أي تقنيات أخرى صعبة ، يمكنك ببساطة مطابقة تدفق الأحداث مع قرابة العنصر:

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

لإزالة النقر خارج مستمع الأحداث ، ببساطة:

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

لتسهيل الاستخدام ، ورمزًا أكثر تعبيرًا ، أنشأت مكون jQuery إضافيًا لهذا:

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

ملاحظة: الهدف هو العنصر الذي نقر عليه المستخدم فعليًا. ولكن لا يزال يتم تنفيذ رد الاتصال في سياق العنصر الأصلي ، لذلك يمكنك الاستفادة من ذلك كما تتوقع في الاستدعاء jQuery.

توصيل في:

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

بشكل افتراضي ، يتم وضع قائمة إصغاء الحدث على المستند. ومع ذلك ، إذا كنت ترغب في تحديد نطاق وحدة إصغاء الحدث ، فيمكنك تمرير كائن jQuery يمثل عنصر مستوى الأصل الذي سيكون هو الأب أو الأم الذي سيتم عنده الاستماع إلى النقرات. هذا يمنع المستمعين الحدث مستوى المستند غير الضرورية. من الواضح أنه لن يعمل ما لم يكن العنصر الرئيسي الذي تم توفيره هو أصل عنصرك الأولي.

استخدام مثل:

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

هنا هو حل جافا سكريبت الفانيلا للمشاهدين في المستقبل.

عند النقر فوق أي عنصر داخل المستند ، إذا كان معرف العنصر الذي تم النقر عليه مثبتًا ، أو إذا كان العنصر المخفي غير مخفي ولا يحتوي العنصر المخفي على العنصر الذي تم النقر عليه ، فقم بتحويل العنصر.

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

إذا كنت ستستخدم أدوات تبديل متعددة في الصفحة نفسها ، فيمكنك استخدام شيء مثل هذا:

  1. قم بإضافة اسم الفئة hiddenإلى العنصر القابل للطي.
  2. عند النقر على المستند ، أغلق جميع العناصر المخفية التي لا تحتوي على العنصر الذي تم النقر عليه ولا تكون مخفية
  3. إذا كان عنصر النقر هو تبديل ، قم بإلغاء تحديد العنصر المحدد.

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


ربط المستمع حدث انقر على المستند. داخل وحدة إصغاء الحدث ، يمكنك الاطلاع على كائن الحدث ، على وجه الخصوص ، event.target لترى العنصر الذي تم النقر عليه:

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

يحتوي الحدث على خاصية تسمى event.path للعنصر وهي "قائمة مرتبة ثابتة لكل أسلافها بترتيب الشجرة" . للتحقق مما إذا كان حدث تم إنشاؤه من عنصر DOM معين أو أحد أطفاله ، ما عليك سوى التحقق من المسار لعنصر DOM المحدد. كما يمكن استخدامه لفحص عناصر متعددة من خلال منطقيا ORالتحقق من العنصر في someالوظيفة.

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

لذلك بالنسبة لقضيتك يجب أن يكون

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

يعمل لي على ما يرام.





jquery