简体   繁体   中英

Make opening 1 div close all other divs of same class (excluding itself) in JS/JQuery?

I'm trying to write JQuery for a set of animated info boxes. Clicking on the title div.info-box__title should open the adjacent div.info-box__content and at the same time close any other open div.info-box__content

Update - should have specified, I also need ALL boxes to close when user clicks outside any .info-box .

Update 2 - Fiddle here: https://jsfiddle.net/q9orfsoy/

The markup is like this:

 <section id="info-box-3" class="info-box">
     <div class="centerer">
         <div class="info-box__close"></div>
         <div class="info-box__title">
             <h1>Title</h1>
         </div>
         <div class="info-box__content">
             <p>content</p>
         </div>
    </div>
</section>

I always struggle with execution order issues with JS. What I have so far are two functions:

Opening:

$('.info-box__title').bind("click touchstart", function() {

    // close the others and open this one
    if($(this).next('.info-box__content').css('display') == 'none') {
        $(this).next('.info-box__content').slideDown();
        $(this).parents('.info-box').addClass('open');
        $(this).parents('.info-box.open').siblings().children('.info-box__title').hide();
    }
});

Closing:

// hide all when click anywhere else in the document
$(document).bind("click touchstart", function(event) {

    // exclude the one that's currently open
    if(!$(event.target).closest('.info-box.open').length){
        $('.info-box__content').slideUp(function(){
            $(this).parents('.info-box').removeClass('open');
        });
    }
});

What this code does is closes all the info-box__content divs when you click outside them. But if you click on another info-box__title it just opens that as well without closing the rest.

(Initially I thought adding a class of .open to the one that's opened would be enough, but I guess I've run into execution order issues?)

What's the best/recommended way to deal with something like this?

Close all then open the one you want with the this object.

$('.info-box__title').click(function() {
    $('.info-box__content').hide(); //or perform closing action
    $(this).siblings('.info-box__content').show(); //or perform opening action
});

To close when clicking outside of any info box,

$('body').not('.info-box').click(function() {
    $('.info-box__content').hide(); //or perform closing action
});

Here is a solution.

  $('.info-box__title').click(function() { var sibling = $(this).siblings('.info-box__content'); if(!sibling.is(':visible')){ $('.info-box__content:visible').slideUp(); sibling.slideDown(); } else sibling.slideUp(); }); $(document).bind("click touchstart", function(e) { var open_content = $(".info-box__content:visible"); if (!open_content.parent().is(e.target) && open_content.parent().has(e.target).length === 0) { open_content.slideUp(); } }); 
 .info-box__title{background:grey;} .info-box__content{ height:100px; display:none; background:red; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <section id="info-box-3" class="info-box"> <div class="centerer"> <div class="info-box__close"></div> <div class="info-box__title"> <h1>Title</h1> </div> <div class="info-box__content"> <p>content</p> </div> </div> </section> <section id="info-box-4" class="info-box"> <div class="centerer"> <div class="info-box__close"></div> <div class="info-box__title"> <h1>Title</h1> </div> <div class="info-box__content"> <p>content</p> </div> </div> </section> <section id="info-box-5" class="info-box"> <div class="centerer"> <div class="info-box__close"></div> <div class="info-box__title"> <h1>Title</h1> </div> <div class="info-box__content"> <p>content</p> </div> </div> </section> 

Try utilizing .index() , jsfiddle https://jsfiddle.net/q9orfsoy/1/

 var titles = $(".info-box__title"); var content = $(".info-box__content"); titles.on("click touchstart", function(e) { if ($(this).next(".info-box__content") .is(":visible")) { $(this).next(".info-box__content") .slideUp() } else { content.slideUp() .eq($(this).index(".info-box__title")) .slideDown() } }); // ALL boxes to close when user clicks outside any `.info-box` $(document).on("click touchstart", function(e) { if ($(e.target).is(".info-box, .info-box *")) { return } else { content.slideUp() } }) 
 .info-box__content { display: none; } .info-box { border: 1px solid black; padding; 20px; margin:20px; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"> </script> <section id="info-box-1" class="info-box"> <div class="centerer"> <div class="info-box__close"></div> <div class="info-box__title"> <h1>Title 1</h1> </div> <div class="info-box__content"> <p>content</p> </div> </div> </section> <section id="info-box-2" class="info-box"> <div class="centerer"> <div class="info-box__close"></div> <div class="info-box__title"> <h1>Title 2</h1> </div> <div class="info-box__content"> <p>content</p> </div> </div> </section> <section id="info-box-3" class="info-box"> <div class="centerer"> <div class="info-box__close"></div> <div class="info-box__title"> <h1>Title 3</h1> </div> <div class="info-box__content"> <p>content</p> </div> </div> </section> 

You could do:

$(document).bind("click touchstart", function(event) {
  var $openBox = $(event.target).closest('.open');
  $('.info-box__content').not($openBox).slideUp(function(){
    $(this).parents('.info-box').removeClass('open');
  });
});

This will select all boxes other than the one related to the click event.

Bonus explanation

The reason your current solution doesn't work is that your just checking to see if the open box exists, since it does, it then closes all elements with the class `.info-box__content'. Hope that makes sense!

Easily slideUp all class while using stop() to slideDown() or slideToggle() target section:

$('.info-box__title').click(function() {
   $('.info-box__content').stop().slideUp();
   $(this).find('.info-box__content').stop().slideDown();
});

$('body').not('.info-box').click(function() {
   $('.info-box__content').stop().slideUp();
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM