7.手风琴
手风琴效果其实就是通过JS改变元素的height,然后加上transition来让css动起来。
准备HTML结构
这里我们使用 dl , 因为 dt 刚好可以模拟标题, dd 模拟内容。
<div class="panel">
<dl>
<dt>One Item</dt>
<dd>One Item Content .</dd>
<dt>two Item</dt>
<dd>two Item Content .</dd>
<dt>3 Item</dt>
<dd>3 Item Content .</dd>
<dt>4 Item</dt>
<dd>4 Item Content .</dd>
</dl>
</div>准备css样式
*{margin: 0;padding: 0;}
.panel{
width: 480px;
min-height: 160px;
margin: 50px auto;
background: #eee;
}
.panel dt{
min-height: 40px;
line-height: 40px;
background: #f9f9f9;
padding-left: 10px;
cursor: pointer;
}
.panel dd{
padding-left: 10px;
height: 0;
overflow: hidden;
transition: height .5s;
}接下来书写我们的JS逻辑
首先我们为我们每一个 dt 绑定 click 事件
同样,我们使用 Array.from 将 NodeList转换为数组,通常能尽量不用for的我就不会用for。
nextElementSibling 代表下一个相邻的元素。
const dtDoms = document.querySelectorAll('dt');
Array.from(dtDoms).forEach((dtDom) => {
dtDom.onclick = (e) => {
const dd = e.target.nextElementSibling; // 被点击的dt的下一个dd元素
toggle(dd);
}
});完成 toggle 函数
function toggle(target){
const ddDoms = document.querySelectorAll('dd');
if(target.style.height == '' || target.style.height == '0px' ) { // 第一次的时候 height 为 ‘’ 空字符串.
for(dd of ddDoms){
dd.style.height = '0px';
}
Object.assign(target.style, {
position: "absolute",
left: "-2000px",
top: "-2000px",
height: "auto",
width: "480px"
});
const height = target.offsetHeight;
target.style.cssText = 'height: 0px';
requestAnimationFrame(() => {
target.style.cssText = 'height: ' + height + 'px';
})
}else{
target.style.height = '0px';
}
}首先为我们要拿到所有的 dd 方便之后重置样式。 然后我们判断目标元素target上面的height, 初始的时候是 ''空字符串,之后就是0px了,当是0px的时候,就说明是关闭状态。
之后我们通过for of遍历所有 dd, 先清空一下未关闭的标签。
然后我们可以通过 Object.assign 来把后面的对象上面的属性拷贝到 target.style 上面去。
通常我们是无法获取一个隐藏元素的高的,所以我们首先把当前的 dd, 用绝对定位定位到屏幕外面去,之后我们就可以通过offsetHeight获取高度了。
有的人会问我为什么不直接用auto, 因为auto是不会产生动画的。 当然你也可以设置一个固定的高度。
之后我们,先把高度重置为0,之后在浏览器重新绘制下一帧的时候再设置高度。
你可以尝试一下去掉requestAnimationFrame,你同样会发现动画失效了。
我猜测可能是浏览器做了处理,短时间的切换属性height会被忽略掉。
Last updated