<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
dl{
border-radius: 3px;
width: 200px;
color: #fff;
}
dt{
height: 30px;
background-color: #333;
}
dd{
height: 100px;
background-color: orange;
}
</style>
</head>
<body>
<dl>
<dt>title1</dt>
<dd></dd>
<dt>title2</dt>
<dd></dd>
<dt>title3</dt>
<dd></dd>
</dl>
<script>
class Animation{
constructor(el){
this.el = el
this.second = 20
this.defaultHeight = this.height
}
get height(){
return window.getComputedStyle(this.el).height.slice(0, -2) * 1
}
set height(val){
this.el.style.height = val + 'px'
}
hide(callback){
let timer = setInterval(() => {
if(this.height <= 0){
clearInterval(timer)
callback && callback()
return
}
this.height = this.height - 1
}, this.second)
}
show(callback){
let timer = setInterval(() => {
if(this.height >= this.defaultHeight){
clearInterval(timer)
callback && callback()
return
}
this.height = this.height + 1
}, this.second)
}
}
class Content extends Animation{
static count = 0
static hideAll(items, callback){
if(Content.count > 0) return
items.forEach((item) => {
Content.count ++
item.hide(() => {
Content.count --
})
})
callback && callback()
}
}
class Accordion{
constructor(wrap, title, content){
this.wrap = document.querySelector(wrap)
this.titles = this.wrap.querySelectorAll(title)
this.contents = [...this.wrap.querySelectorAll(content)].map(item => new Content(item))
this.bindEvent()
}
bindEvent(){
let count = 0
this.titles.forEach((title, i) => {
title.addEventListener('click', () => {
Content.hideAll(this.filterContent(this.contents, i), this.contents[i].show.bind(this.contents[i]))
})
});
}
filterContent(contents, i){
return contents.filter((item, index) => index != i)
}
}
let accordion = new Accordion('dl', 'dt', 'dd')
</script>
</body>
</html>