发布于 

JS+CSS手风琴动画效果

手风琴动画效果:当点击某个选项卡时,该选项卡展示内容,其他选项卡的内容收起,无论展示还是收起都带有过渡效果

效果图如下:

手风琴效果图

思路:为每个选项卡设置点击事件,修改dom元素样式

难点:过渡动画的实现。刚开始我使用display:blockdisplay:none控制内容的显示与隐藏,但是发现display并没有动画效果,后来想使用height,但元素高度不固定(高度由内容撑开),也没法实现动画效果。

最后百度找到一个解决方法:使用maxHeight作为过渡效果的CSS属性,使用css设置内容元素的maxHeight为0,并且使用overflow:hidden隐藏溢出内容。当点击选项卡时,使用JS获取内容元素的真实高度(dom.scrollHeight),再把真实高度赋值给内容元素的maxHeight即可。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<div class="container">
<h2>手风琴动画</h2>
<button class="accordion">选项1</button>
<div class="panel">
<ul>
<li>
<a href="">Overview</a>
</li>
<li>
<a href="">Microservices</a>
</li>
<li>
<a href="">Overview</a>
</li>
</ul>
</div>
<button class="accordion">选项2</button>
<div class="panel">
<ul>
<li>
<a href="">Quickstart</a>
</li>
</ul>
</div>
<button class="accordion">选项3</button>
<div class="panel">
<ul>
<li>
<a href="">Events</a>
</li>
<li>
<a href="">Team</a>
</li>
</ul>
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
ul{
list-style: none;
padding: 0;
margin: 0;
}
a {
text-decoration: none;
color: black;
}
.container {
width: 600px;
margin: 0 auto;
text-align: center;
background: #191e1e;
color: white;
}
button.accordion {
background-color: #191e1e;
color: white;
cursor: pointer;
padding: 16px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 18px;
transition: 0.4s;
}
button.accordion.active,
button.accordion:hover {
background-color: rgb(110, 109, 109);
}
div.panel {
/*过渡效果主要代码*/
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
.panel a{
background: #191e1e;
display: block;
padding: 10px 20px;
color: #98afae;
text-align: left;
font-size: 16px;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let acc = document.querySelectorAll('.accordion');
let panelList = document.querySelectorAll('.panel')
//为每个选项卡绑定点击事件
acc.forEach((ele,index)=>{
ele.onclick = function(){
this.classList.toggle('active');
let panel = panelList[index];
if(panel.style.maxHeight){ //如果元素maxHeight存在,表示内容正在展开,需要隐藏
panel.style.maxHeight = null
}else{
//获取元素的真实高度
panel.style.maxHeight = panel.scrollHeight+"px";
}
//排他:将非选中的选项卡内容隐藏
acc.forEach((e,i)=>{
if(index!=i){
ele.classList.remove('active')
panelList[i].style.maxHeight = null
}
})
}
})