Dom navigation for custom jQuery accordion setup

I have an accordion working and it works really well when you go down the accordions, but when you come back it looks like a buggy one.

I want to do this, when you click on a mast, it will open the content inside that mast and anchor the top of the page to the top of the mast. I know what I need to do in pseudocode, but I'm not sure what to actually do with the code.

Here's my HTML:

<html>
<head>
    <meta>
    <title></title>
    <link rel="stylesheet" href="made-insider.css">
</head>
<body>
    <div class="accordion">
        <div id="one" class="masthead"></div>
        <div class="insider-info"></div>

        <div id="two" class="masthead"></div>
        <div class="insider-info"></div>

        <div id="three" class="masthead"></div>
        <div class="insider-info"></div>

        <div id="four" class="masthead"></div>
        <div class="insider-info"></div>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script src="made-insider.js"></script>
</body>
</html>

      

Here's my jQuery:

$(function() {

  //Checking the position of panels
  var allPanels = $('.insider-info').hide();

  //working accordion code -- needs to be smoother
  $('.accordion > .masthead').click(function(event) {

    if ($(this).hasClass('active')) {
        $(this).removeClass('active')
            .next(allPanels).slideUp(400);
    } else {
      var topPos = $(this).position();
        $('.active').removeClass('active')
            .next(allPanels).slideUp(400);
      //if the previous accordion is open
        $('body').animate({ scrollTop: topPos.top - 200}, 600);
      //if the previous accordion is not open
        //$('body').animate({ scrollTop: topPos.top}, 600);
        $(this).addClass('active')
            .next(allPanels).slideDown(400);
    }
  });

});

      

I have tried things like

if ($(this).prev('.masthead').hasClass('.active')){
    behavior
}, 


if ($(this).prev().prev().hasClass('.active'){
    behavior
}

if ($(this).eq() < $('div.active').eq()){
    behavior
} 

      

but none of them work. Any suggestions?

+3


source to share


2 answers


The problem is that the place in your code where you need to know the index .active

is triggered after you remove the class .active

from any of its elements.

Solution: move this bit of code

$('.active').removeClass('active')
    .next(allPanels).slideUp(400);

      

to the end of the event handler, before adding the class .active

to the new active element.

Then the condition you are looking for is



if ($('.active').length && $('.active').index() < $(this).index()) {
    // the previously active accordion is above the new one (we're moving down)
}

      

So, put together, you will look like this:

$('.accordion > .masthead').click(function (event) {

    if ($(this).hasClass('active')) {
        $(this).removeClass('active')
            .next(allPanels).slideUp(400);
    } else {
        var topPos = $(this).position();

        // the previously active accordion is above the new one
        if ($('.active').length && $('.active').index() < $(this).index()) {
            $('body').animate({
                scrollTop: topPos.top - 200
            }, 600);
        } else { // the previously active accordion is below the new one, or there was no previous accordion
            $('body').animate({
                scrollTop: topPos.top
            }, 600);
        }

        $('.active').removeClass('active')
            .next(allPanels).slideUp(400);
        $(this).addClass('active')
            .next(allPanels).slideDown(400);
    }
});

      

JSFiddle Here

+2


source


I spent a day this weekend to really clean up the code and improve its functionality.

This code will allow you to create an accordion that is anchored to the top of the tab you click on and is designed to respond to both the size of the mast tab and the content in the tab. Any suggestions on how I could make the code even cleaner would be great!



Check out the code on my GitHub if you like: https://github.com/realjoet/smooth-flexible-accordion

$(function () {
  //Checking the position of panels
  var allContentPanels = $('.content');
  var allMastheads = $('.masthead');
  var hideContentPanels = allContentPanels.hide();
  //If you want margin on your mastheads, enter it here just like CSS
  var mastheadMargin = "0";
  //Need to fill these in with negative values of the values you put in for mastheadMargin
  var marginTopFix = "0";
  var marginRightFix = "0";
  var marginBottomFix = "0";
  var marginLeftFix = "0";

  allMastheads.css("margin", mastheadMargin);

  //working accordion code
  $('.accordion > .masthead').click(function() {
    var el = $(this);
    var activeEl = $('.active');
    var contentHeight = $('.active').next().height();
    var topPos = $(this).position().top;

    function marginFix(el) {
      $(el).next().css({
        "position": "relative", 
        "top": marginTopFix, 
        "right": marginRightFix, 
        "bottom": marginBottomFix, 
        "left": marginLeftFix
      }).delay(10);
    }

    //Accordion function
    function accordionFunc(el, animationTime, animationTime2) {
      if (el.hasClass('active')) {
        el.removeClass('active')
          .next(allContentPanels).slideUp(animationTime);
        $('body').animate({scrollTop: topPos}, animationTime);
      } else {
        if (activeEl.length && activeEl.index() < el.index()) {
          $('body').animate({scrollTop: topPos - contentHeight}, animationTime2);
        } else { 
          $('body').animate({scrollTop: topPos}, animationTime2);
        }

        activeEl.removeClass('active')
          .next(allContentPanels).slideUp(animationTime);
        el.addClass('active')
          .next(allContentPanels).slideDown(animationTime);
      }
    }

    //Adjusts masthead margins
    if (el.hasClass('active')) {
      marginFix(el);
      $(allMastheads).css("margin", mastheadMargin);
    } else {
      marginFix(activeEl);
      $(allMastheads).css("margin", mastheadMargin);
      el.css("margin", "0");
      el.next().css("margin", mastheadMargin);
      if (el.next().css("top") == marginTopFix) {
        el.next().css("top", "0");
      }
    }

    //Creates content-responsive accordion
    if (contentHeight < 400) {
      accordionFunc(el, 600, 800);
    } else if (contentHeight < 800) {
      accordionFunc(el, 800, 1000);
    } else if (contentHeight < 1200) {
      accordionFunc(el, 1000, 1200);
    } else {
      accordionFunc(el, 1200, 1400);
    }
  });
});

      

0


source







All Articles