原生JS(无jQuery)结合Promise/async/await实现淡入淡出替换元素问题排查
原生JS淡入淡出切换动画失效问题修复
核心错误点
代码一共存在3个直接导致效果异常的问题:
- Promise未正确决议,异步流程卡断:
fadeOut函数内部全程没有调用resolve(),当1秒淡出动画执行完成后,返回的Promise永远处于pending状态,await会一直卡在这一行,后续的fadeIn逻辑根本不会被执行,新元素自然一直保持初始透明状态无法显示。 fadeIn的resolve时机错误:fadeIn里把resolve(elem)写在了setInterval启动逻辑的外部,动画刚初始化就直接返回,根本不会等待淡入动画执行完成,无法保证时序控制。- 空元素分支未处理Promise状态:两个动画函数里判断
!elem直接return的分支,都没有决议Promise,一旦传入不存在的元素会直接导致整个异步流程永久挂起。
修正后的完整代码
HTML代码
<div id="main"> <div class="x"> blah </div> </div>
CSS代码
.asd1 { width: 100px; height: 100px; background-color: red; opacity: 0; } .x { width: 50px; height: 50px; background-color: purple; }
JavaScript代码
const main = document.querySelector('#main'); const el0 = document.querySelector('.x'); const str = '<div class="asd1">Hello</div>'; // generated from fetch result main.insertAdjacentHTML('beforeend', str); const el1 = document.querySelector('.asd1'); (async() => { await fadeOut(el0, 1000); await fadeIn(el1, 1000); })(); function fadeIn(elem, ms) { return new Promise((resolve) => { if (!elem) { resolve(); return; } elem.style.opacity = 0; elem.style.filter = "alpha(opacity=0)"; elem.style.display = "inline-block"; elem.style.visibility = "visible"; if (ms) { let opacity = 0; const timer = setInterval(function() { opacity += 50 / ms; if (opacity >= 1) { clearInterval(timer); opacity = 1; resolve(elem); } elem.style.opacity = opacity; elem.style.filter = "alpha(opacity=" + opacity * 100 + ")"; }, 50); } else { elem.style.opacity = 1; elem.style.filter = "alpha(opacity=1)"; resolve(elem); } }); } function fadeOut(elem, ms) { return new Promise((resolve) => { if (!elem) { resolve(); return; } if (ms) { let opacity = 1; const timer = setInterval(function() { opacity -= 50 / ms; if (opacity <= 0) { clearInterval(timer); opacity = 0; elem.style.display = "none"; elem.style.visibility = "hidden"; resolve(elem); } elem.style.opacity = opacity; elem.style.filter = "alpha(opacity=" + opacity * 100 + ")"; }, 50); } else { elem.style.opacity = 0; elem.style.filter = "alpha(opacity=0)"; elem.style.display = "none"; elem.style.visibility = "hidden"; resolve(elem); } }); }
补充说明:如果不需要兼容IE8及更早版本,完全不需要手动写setInterval实现动画,用原生CSS
transition搭配transitionend事件监听实现动画,代码更简洁、性能更好。
内容的提问来源于stack exchange,提问作者dapidmini
相关产品推荐
相关产品推荐

