今天记录一个js小技巧 既不用setTimeout 也不用监听transitioned事件 实现display:block/none的显示隐藏动画
准备工作
dom元素和css准备,先实现一个简单的弹窗样式和一个控制按钮,觉得繁琐的直接跳到第1步看核心代码,不心急吃热豆腐的可以跟着我一起回顾弹窗的垂直居中css实现方式
<style>
.content {
/* 四行css实现垂直居中 */
position: relative;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
height: 200px;
width: 200px;
background-color: #fff;
}
.dialog {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.2);
opacity: 0;
display: none;
transition: opacity 1s ease;
}
.dialog.block {
display: block;
}
.dialog.visible {
opacity: 1;
transition: opacity 1s ease;
}
</style>
<button type="button" onclick="change()">弹窗</button>
<div class="dialog">
<div class="content">
<p>我是弹窗,嘿嘿</p>
</div>
</div>
<body>
<button type="button" onclick="change()">弹窗</button>
<div class="dialog">
<div class="content">
<p>我是弹窗,嘿嘿</p>
</div>
</div>
</body>
JS控制显示隐藏
我们都知道css的opacity、width、height、margin等属性可以通过transition实现过渡效果。
但是display确不行,背后到底隐藏了什么秘密目前我也没搞懂,其可能的原因是display设置为block后,浏览器将其渲染到页面的过程是ui render,这个过程是一个宏任务,而js会优先执行同步代码,所以先执行了opacity:1。
如果在设置了block后,立马获取元素的clientHeight、offsetHeight属性,就会先在页面绘制dialog,然后执行过度动画。这其中又是什么原理,我也没搞懂,暂时记录一下
var dialogEl = document.querySelector(".dialog");
function change() {
dialogEl.classList.add("block");
// 最关键的是这一步,可以保证元素先渲染到页面,再执行opacity:1,
// 除此之外还有offsetWidth、scrollHeight均有相同的效果
dialogEl.clientHeight;
dialogEl.classList.add("visible");
}
效果展示: