Reputation: 397
I have this JSfiddle: https://jsfiddle.net/07fdq3t1/5/
It's almost perfect, except I'd like to have it to where the content is displayed in an animated fashion. Right now it just pops open, but I'd like to have it slowly open. The animation for making it go to the top of the viewport is working great, but I need it to where when someone clicks an element, the content opens up slowly.
Any ideas?
<script>
$(document).ready(function() {
$('.accordion').click(function(){
if($(this).next('.container').is(':visible')) {
$(this).removeClass('show');
$(this).next('.container').slideUp();
}
else {
$('.accordion').find('.container:visible').slideUp();
$('.accordion').removeClass('show');
$(this).addClass('show');
$(this).next('.container').slideDown();
$('html, body').animate({
scrollTop: $(this).offset().top
}, 200);
}
});
});
</script>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
Upvotes: 1
Views: 3825
Reputation: 5737
All right. Here is my attempt in solving your problem. Have a look at the fiddle or snippet below.
Snippet:
var accordions=null;
var containers=null;
var slideDuration=400;
var scrollDuration=400;
var body=null;
var classNameShow='show';
var classNameAccordion='.accordion';
var classNameContainer='.container';
var dataOffsetTop='offsetTop';
$(document).ready(function(){
body=$('html, body');
accordions=$(classNameAccordion);
containers=$(classNameContainer);
accordions.each(function(){
var openedAccordions=accordions.filter(function(){return $(this).hasClass(classNameShow);});
openedAccordions.removeClass(classNameShow);
$(this).data(dataOffsetTop,$(this).offset().top);
openedAccordions.next(classNameContainer).stop(true).slideDown({
duration:slideDuration,
complete:function(){openedAccordions.addClass(classNameShow);}
});
});
accordions.click(function(){
var currentAccordion=$(this);
var currentContainer=$(this).next(classNameContainer);
var openedAccordions=accordions.filter(function(){return $(this).hasClass(classNameShow);});
if(!currentAccordion.hasClass(classNameShow)){
currentContainer.stop(true).slideDown({
duration:slideDuration,
complete:function(){currentAccordion.addClass(classNameShow);}
});
body.stop(true).animate({scrollTop:currentAccordion.data(dataOffsetTop)},scrollDuration);
}else{
currentContainer.stop(true).slideUp({
duration:slideDuration,
complete:function(){currentAccordion.removeClass(classNameShow);}
});
}
containers.not(currentContainer).stop(true).slideUp({
duration:slideDuration,
complete:function(){openedAccordions.removeClass(classNameShow);}
});
});
});
.accordion {
margin: 0;
padding: 10px;
height: 20px;
border-top: #f0f0f0 1px solid;
background: #cccccc;
font-family: Arial, Helvetica, sans-serif;
text-decoration: none;
text-transform: uppercase;
color: #000;
font-size: 1em;
}
.accordion span {
background: #000;
color: #fff;
}
.show span {
display: block;
float: right;
padding: 10px;
}
.accordion span {
display: block;
float: right;
background: url(http://www.snyderplace.com/demos/images/plus.png) center center no-repeat;
padding: 10px;
}
.show span {
background: url(http://www.snyderplace.com/demos/images/minus.png) center center no-repeat;
}
div.container {
padding: 0;
margin: 0;
display: none;
}
div.content {
background: #f0f0f0;
margin: 0;
padding: 10px;
font-size: .9em;
line-height: 1.5em;
font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
}
div.content ul, div.content p {
margin: 0;
padding: 3px;
}
div.content ul li {
list-style-position: inside;
line-height: 25px;
}
div.content ul li a {
color: #555555;
}
div.show + .container {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p></div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion show">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
<div class="accordion">Heading<span></span></div>
<div class="container">
<div class="content">
<div>Sample Content</div>
<p>Content here....</p>
</div>
</div>
Summary: (not really)
each
block is to calculate the destination scrollTop
values based on the offset.top()
positions of all of the accordion elements. Which is then stored in data()
property for each accordion
element.show
class applied to them and stores them in a variable called openedAccordions
.show
class from them.offset.top()
position of each element and stores in the elements themselves using the convenient data()
method provided by jQuery.show
class using addClass()
method, we actually animate using the slideDown()
method and only upon completion of the animation, we apply show
using addClass()
.show
using addClass()
without animation produces an unwanted glitch the first time you, as a user, interact with this whole component. The glitch is basically your first already visible container
element that goes away rather instantly, without animation.offset().top
position of any given accordion element which may not exactly be what we require i.e. the animation may be in progress and the calculated result coming out of offset().top
may be wrong and hence the browser will scroll to an unwanted position. I hope you understand what I am to trying to say here.accordion
elements, some internal variables are defined and their values are set.if
clause checking if the element has class named show
applied to it.:visible
state, I chose to simply look for a class' existence on an element.if
clause should be pretty self-explanatory.slideUp
to animate the elements so the openedAccordions
elements can hide except the one that was just clicked. I hope I am making sense here.Hope this helps.
P.S. I guess the cool bit for me is how it would re-adjust upon fast clicking. Try increasing the scrollDuration
and slideDuration
values to make all animations go slower and click on random accordion
elements to see what I mean by re-adjusting.
Upvotes: 1
Reputation: 5948
Yep, just use the slideUp()
and slideDown()
methods instead of simply adding the show
class.
Upvotes: 1
Reputation: 2731
Just made your slide up remove the show class on completion and the slideDown function be used at the end for your container on show.
$(document).ready(function() {
$('.accordion').click(function(){
if($(this).next('.container').is(':visible')) {
var self = $(this);
$(this).next('.container').slideUp(800,function() {
self.removeClass('show');
});
}
else {
$('.accordion').find('.container:visible').slideUp();
$('.accordion').removeClass('show');
$(this).addClass('show');
$(this).next('.container').slideDown();
$('html, body').animate({
scrollTop: $(this).offset().top
}, 200);
$(this).slideDown();
}
});
});
Here it is running: https://jsfiddle.net/07fdq3t1/6/
Upvotes: 0