คลิกเมนูด้านนอกเพื่อปิดใน jquery


107

ฉันจึงมีเมนูแบบเลื่อนลงที่แสดงให้เห็นเมื่อคลิกตามความต้องการทางธุรกิจ เมนูจะถูกซ่อนอีกครั้งหลังจากที่คุณวางเมาส์จากเมนู

แต่ตอนนี้ฉันถูกขอให้ติดตั้งไว้จนกว่าผู้ใช้จะคลิกที่ใดก็ได้บนเอกสาร จะสำเร็จได้อย่างไร?

นี่เป็นเวอร์ชันที่เรียบง่ายของสิ่งที่ฉันมีตอนนี้:

$(document).ready(function() {
  $("ul.opMenu li").click(function(){
   $('#MainOptSubMenu',this).css('visibility', 'visible');
  });

  $("ul.opMenu li").mouseleave(function(){
      $('#MainOptSubMenu',this).css('visibility', 'hidden');
  });
});



<ul  class="opMenu">
  <li id="footwo" class="">
    <span id="optImg" style="display: inline-block;"> <img src="http://localhost.vmsinfo.com:8002/insight/images/options-hover2.gif"/> </span>
      <ul id="MainOptSubMenu" style="visibility: hidden; top: 25px; border-top: 0px solid rgb(217, 228, 250); background-color: rgb(217, 228, 250); padding-bottom: 15px;">
        <li>some</li>
       <li>nav</li>
       <li>links</li>
       </ul>
    </li>
</ul> 

ฉันลองทำอะไรแบบนี้โดย$('document[id!=MainOptSubMenu]').click(function()คิดว่ามันจะเกิดขึ้นกับอะไรก็ได้ที่ไม่ใช่เมนู แต่มันไม่ได้ผล



คำตอบ:


196

ดูแนวทางที่คำถามนี้ใช้:

ฉันจะตรวจจับการคลิกนอกองค์ประกอบได้อย่างไร

แนบเหตุการณ์การคลิกเข้ากับเนื้อหาของเอกสารซึ่งจะปิดหน้าต่าง แนบเหตุการณ์การคลิกแยกต่างหากเข้ากับหน้าต่างซึ่งหยุดการเผยแพร่ไปยังเนื้อหาของเอกสาร
$('html').click(function() {
  //Hide the menus if visible
});

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


16
มันสวยงามมาก แต่คุณควรใช้ $ ('html') คลิก () ไม่ใช่ body ร่างกายมักจะมีความสูงของเนื้อหา มีเนื้อหาไม่มากหรือหน้าจอสูงมากใช้งานได้เฉพาะส่วนที่เต็มไปด้วยร่างกายเท่านั้น คัดลอกจาก: stackoverflow.com/questions/152975/… - meo 25 ก.พ. 54 เวลา 15:35 น.
NickGreen

ทางออกที่ดี มีความคิดว่าทำไมจึงใช้กับ. click () และไม่ใช้กับ. live ('click', func ... ?
หาดใหญ่

3
ปัญหาเดียวของแนวทางนี้คืออ็อบเจ็กต์ที่มี click listener อยู่แล้วซึ่ง stopPropagation ด้วยเหตุผลอื่นไม่มีผล ฉันเข้าใจว่าเหตุใดจึงเป็นเช่นนั้น แต่ก็ยังมีข้อ จำกัด ของโซลูชันนี้
DanH

53

คำตอบนั้นถูกต้อง แต่จะเพิ่ม Listener ที่จะถูกเรียกทุกครั้งที่เกิดการคลิกบนเพจของคุณ เพื่อหลีกเลี่ยงสิ่งนั้นคุณสามารถเพิ่มผู้ฟังเพียงครั้งเดียว:

$('a#menu-link').on('click', function(e) {
    e.preventDefault();
    e.stopPropagation();

    $('#menu').toggleClass('open');

    $(document).one('click', function closeMenu (e){
        if($('#menu').has(e.target).length === 0){
            $('#menu').removeClass('open');
        } else {
            $(document).one('click', closeMenu);
        }
    });
});

แก้ไข: หากคุณต้องการหลีกเลี่ยงstopPropagation()ปุ่มเริ่มต้นคุณสามารถใช้สิ่งนี้ได้

var $menu = $('#menu');

$('a#menu-link').on('click', function(e) {
    e.preventDefault();

    if (!$menu.hasClass('active')) {
        $menu.addClass('active');

        $(document).one('click', function closeTooltip(e) {
            if ($menu.has(e.target).length === 0 && $('a#menu-link').has(e.target).length === 0) {
                $menu.removeClass('active');
            } else if ($menu.hasClass('active')) {
                $(document).one('click', closeTooltip);
            }
        });
    } else {
        $menu.removeClass('active');
    }
});

ฉันเห็นรหัสแบบนี้มากสิ่งนี้จะไม่เพิ่มฟังก์ชันการคลิกใหม่ลงในเอกสารทุกครั้งที่คลิกลิงก์เมนูหรือไม่ ดังนั้นหากคุณคลิกลิงก์เมนู 1,000 ครั้งโดยไม่รีเฟรชหน้าคุณจะมีฟังก์ชันมากกว่า 1,000 ฟังก์ชันที่ใช้หน่วยความจำและกำลังดำเนินการอยู่?
eselk

ไม่เป็นไรฉันไม่เห็นฟังก์ชัน "one" ตอนนี้ฉันเข้าใจแล้วว่าทำไมถึงได้ผล: api.jquery.com/one
eselk

2
ทางออกที่ดี แต่ฉันต้องใช้e.stopPropagation()ใน Chrome เพื่อหยุดเหตุการณ์แรกจากการยิงในone()ตัวจัดการ
antfx

18

stopPropagationตัวเลือกที่ดีเพราะพวกเขาสามารถยุ่งเกี่ยวกับการจัดการเหตุการณ์อื่น ๆ รวมถึงเมนูอื่น ๆ ที่อาจได้แนบไสใกล้กับองค์ประกอบของ HTML

นี่คือวิธีง่ายๆตามคำตอบของuser2989143 :

$('html').click(function(event) {
    if ($(event.target).closest('#menu-container, #menu-activator').length === 0) {
        $('#menu-container').hide();
    }
});

17

หากคุณใช้ปลั๊กอินได้ฉันขอแนะนำปลั๊กอิน clickoutside ของ Ben Alman ซึ่งอยู่ที่นี่ :

การใช้งานทำได้ง่ายดังนี้:

$('#menu').bind('clickoutside', function (event) {
    $(this).hide();
});

หวังว่านี่จะช่วยได้


8

2 ตัวเลือกที่คุณตรวจสอบได้:

  • ในการแสดงเมนูให้วาง DIV ว่างขนาดใหญ่ไว้ด้านหลังปิดส่วนที่เหลือของหน้าและให้เหตุการณ์คลิกเพื่อปิดเมนู (และตัวมันเอง) ซึ่งคล้ายกับวิธีการที่ใช้กับไลท์บ็อกซ์ซึ่งการคลิกที่พื้นหลังจะปิดไลท์บ็อกซ์
  • ในการแสดงเมนูให้แนบตัวจัดการเหตุการณ์แบบคลิกครั้งเดียวบนเนื้อหาที่ปิดเมนู คุณใช้ '.one ()' ของ jQuery สำหรับสิ่งนี้

6

ฉันพบโซลูชันของ Grsmto หลายรูปแบบและโซลูชันของเดนนิสช่วยแก้ปัญหาของฉันได้

$(".MainNavContainer").click(function (event) {
    //event.preventDefault();  // Might cause problems depending on implementation
    event.stopPropagation();

    $(document).one('click', function (e) {
        if(!$(e.target).is('.MainNavContainer')) {
            // code to hide menus
        }
    });
});

5

ฉันใช้โซลูชันนี้กับหลายองค์ประกอบที่มีพฤติกรรมเดียวกันในหน้าเดียวกัน:

$("html").click(function(event){
    var otarget = $(event.target);
    if (!otarget.parents('#id_of element').length && otarget.attr('id')!="id_of element" && !otarget.parents('#id_of_activator').length) {
        $('#id_of element').hide();
    }
});

stopPropagation () เป็นความคิดที่ไม่ดีซึ่งเป็นการทำลายพฤติกรรมมาตรฐานของหลาย ๆ สิ่งรวมถึงปุ่มและลิงก์


นี่เป็นสิ่งที่ดี แต่คุณสามารถทำให้มันง่ายขึ้นได้$target.closest('#menu-container, #menu-activator').length === 0
Code Commander

5

ฉันเพิ่งเผชิญกับปัญหาเดียวกันนี้ ฉันเขียนรหัสต่อไปนี้:

    $('html').click(function(e) {
      var a = e.target;
      if ($(a).parents('.menu_container').length === 0) {
        $('.ofSubLevelLinks').removeClass('active'); //hide menu item
        $('.menu_container li > img').hide(); //hide dropdown image, if any
     }
    });

มันได้ผลสำหรับฉันอย่างสมบูรณ์แบบ


4

แล้วนี่?

    $(this).mouseleave(function(){  
        var thisUI = $(this);
        $('html').click(function(){
                thisUI.hide();
            $('html').unbind('click');
         });
     });

3

ฉันคิดว่าการใช้ mousedown-event แทน click-event มีประโยชน์มากกว่า เหตุการณ์คลิกจะไม่ทำงานหากผู้ใช้คลิกที่องค์ประกอบอื่น ๆ บนเพจที่มีเหตุการณ์คลิก เมื่อใช้ร่วมกับวิธี one () ของ jQuery จะมีลักษณะดังนี้:

$("ul.opMenu li").click(function(event){

   //event.stopPropagation(); not required any more
   $('#MainOptSubMenu').show();

   // add one mousedown event to html
   $('html').one('mousedown', function(){
       $('#MainOptSubMenu').hide();
   });
});

// mousedown must not be triggered inside menu
$("ul.opMenu li").bind('mousedown', function(evt){
    evt.stopPropagation();
});

3

แม้ว่าฉันจะเจอสถานการณ์เดียวกันและที่ปรึกษาคนหนึ่งของฉันก็นำความคิดนี้มาใช้กับตัวเอง

ขั้นตอน: 1 เมื่อคลิกที่ปุ่มที่เราควรจะแสดงเมนูแบบเลื่อนลง จากนั้นเพิ่มชื่อคลาสด้านล่าง "more_wrap_background" ในหน้าที่ใช้งานอยู่ในปัจจุบันดังที่แสดงด้านล่าง

$('.ui-page-active').append("<div class='more_wrap_background' id='more-wrap-bg'> </div>");

ขั้นตอนที่ 2 จากนั้นเพิ่มการคลิกสำหรับแท็ก div เช่น

$(document).on('click', '#more-wrap-bg', hideDropDown);

โดยที่ hideDropDown เป็นฟังก์ชันที่จะเรียกใช้เพื่อซ่อนเมนูแบบเลื่อนลง

ขั้นตอนที่ 3 และขั้นตอนที่สำคัญในขณะที่ซ่อนเมนูแบบเลื่อนลงคือการลบคลาสนั้นที่คุณเพิ่มไว้ก่อนหน้านี้เช่น

$('#more-wrap-bg').remove();

ฉันกำลังลบโดยใช้ id ในโค้ดด้านบน

.more_wrap_background {
  top: 0;
  padding: 0;
  margin: 0;
  background: rgba(0, 0, 0, 0.1);
  position: fixed;
  display: block;
  width: 100% !important;
  z-index: 999;//should be one less than the drop down menu's z-index
  height: 100% !important;
}

2
$("html").click( onOutsideClick );
onOutsideClick = function( e )
{
    var t = $( e.target );
    if ( !(
        t.is("#mymenu" ) ||     //Where #mymenu - is a div container of your menu
        t.parents( "#mymenu" ).length > 0
        )   )
    {
        //TODO: hide your menu
    }
};

และจะดีกว่าในการตั้งค่าผู้ฟังเฉพาะเมื่อเมนูของคุณมองเห็นได้และจะลบผู้ฟังเสมอหลังจากที่เมนูถูกซ่อน


1

ฉันคิดว่าคุณต้องการสิ่งนี้: http://jsfiddle.net/BeenYoung/BXaqW/3/

$(document).ready(function() {
  $("ul.opMenu li").each(function(){
      $(this).click(function(){
            if($(this).hasClass('opened')==false){          
                $('.opMenu').find('.opened').removeClass('opened').find('ul').slideUp();
                $(this).addClass('opened'); 
                $(this).find("ul").slideDown();
            }else{
                $(this).removeClass('opened'); 
                $(this).find("ul").slideUp();               
            }
      });
  });    
});

ฉันหวังว่ามันจะเป็นประโยชน์สำหรับคุณ!


1

ใช้ตัวเลือก ": visible" โดยที่ .menuitem เป็นองค์ประกอบที่จะซ่อน ...

$('body').click(function(){
  $('.menuitem:visible').hide('fast');
});

หรือถ้าคุณมีองค์ประกอบ .menuitem อยู่แล้วในตัวแปร ...

var menitems = $('.menuitem');
$('body').click(function(){
  menuitems.filter(':visible').hide('fast');
});

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.