You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用原生JavaScript实现类VueJS的过渡效果?

解决原生JS模拟Vue过渡时淡入失效的问题

我来帮你搞定这个淡入没效果的问题!你的淡出逻辑是对的,但淡入时的DOM操作时机出了问题——浏览器会把连续的样式变更合并成一次重绘,直接跳过了过渡需要的初始透明状态,导致过渡完全没触发。

问题根源

当你点击show按钮时,你连续做了这几步:

  1. 移除hide类(元素从display:none变成默认的display:flex)
  2. 添加div-enter类(opacity:0)
  3. 立刻替换成div-enter-to类(opacity:1)

浏览器会把这三个操作合并成一次渲染,直接让元素以opacity:1显示,完全没有过渡的过程,自然也不会触发transitionend事件。

修复方案

我们需要给浏览器一个“缓冲时间”,让它先渲染出元素显示且透明的状态,再切换到完全可见的状态。用requestAnimationFrame就能完美实现这个效果(它会在浏览器下一次重绘前执行回调)。

修改后的完整代码

HTML(无需改动)

<button id="btnShow">show</button>
<button id="btnHide">hide</button>
<div> fade out, then set display: none<br /> then do the reverse... </div>

CSS(优化过渡目标,移除无效属性)

.hide { display: none; } /* 移除opacity:0,因为display:none时它无效 */
.div-enter { opacity: 0; }
.div-enter-to { opacity: 1; }
.div-leave { opacity: 1; }
.div-leave-to { opacity: 0; }

/* 原有样式保留,优化过渡属性 */
html, body { height: 100vh; width: 100vw; margin: 0; padding: 1em 1.5em; font-size: 100%; }
div { 
  display: flex; 
  align-items: center; 
  justify-content: center; 
  flex-direction: column; 
  margin: 1em 0; 
  padding: 3rem 0; 
  width: 50%; 
  background: #4bfa; 
  border-radius: 5px; 
  transition: opacity 1s linear; /* 只针对opacity过渡,提升性能 */
}
button { border: none; border-radius: 2px; }
button:hover { cursor: pointer; }

JavaScript(调整淡入逻辑的时机)

const btnShow = document.querySelector('#btnShow');
const btnHide = document.querySelector('#btnHide');
const div = document.querySelector('div');

btnShow.addEventListener('click', () => {
  console.log('btnShow clicked');
  div.classList.remove('hide');
  // 先设置初始透明状态
  div.classList.add('div-enter');
  
  // 让浏览器先渲染初始状态,再触发过渡
  requestAnimationFrame(() => {
    div.classList.replace('div-enter', 'div-enter-to');
  });
  
  div.addEventListener('transitionend', function() {
    console.log('show transition ended');
    div.classList.remove('div-enter-to');
  }, { once: true });
});

btnHide.addEventListener('click', () => {
  console.log('btnHide clicked');
  div.classList.add('div-leave');
  div.classList.replace('div-leave', 'div-leave-to');
  div.addEventListener('transitionend', () => {
    console.log('hide transition ended');
    div.classList.replace('div-leave-to', 'hide');
  }, { once: true });
});

关键改动说明

  1. CSS优化:把过渡从all改成opacity,避免其他属性(比如布局相关)意外触发过渡,同时移除hide类里无效的opacity:0。
  2. JS淡入逻辑:用requestAnimationFrame延迟切换到div-enter-to类,让浏览器有时间渲染出元素显示但透明的状态,这样过渡动画就能正常触发了。

现在点击show按钮,元素会从透明慢慢淡入,也能正常触发transitionend事件啦!

内容的提问来源于stack exchange,提问作者user1960364

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 09:43:10