BarbaJS动画异常:返回首页时动画卡顿停止问题排查
问题解决:BarbaJS页面切换动画黑屏冻结问题
需求说明
- 每次进入首页时,对应的入场动画需正常触发
- 不同页面间切换需使用不同类型的动画
问题现象
从项目页返回首页时,动画停止,出现黑屏冻结,无法正常完成过渡。
复现步骤
- 滚动至“Kiddy”项目并点击VIEW PROJECT
- 待动画完成后,滚动至页面顶部点击LOGO,触发黑屏冻结异常
相关代码
JS代码
// entryAnimation const text = document.querySelector(".preloader__text--content"); const strText = text.textContent; const splitText = strText.split(""); text.textContent = ""; for (let i = 0; i < splitText.length; i++) { text.innerHTML += "<span>" + splitText[i] + "</span>" } let char = 0; let timer = setInterval(onTick, 50); function onTick(){ const span = text.querySelectorAll('span')[char] span.classList.add('fade'); console.log(char) char++; if(char===splitText.length){ complete(); setTimeout(() => { preloader.classList.add('hide'); }, 1500); return; } } function complete(){ clearInterval(timer); timer = null; } barba.use(barbaCss); // barba.hooks.enter(() => { // window.scrollTo(0, 0); // }); barba.init({ transitions: [ { name: 'cover', to:{ namespace: ['home', 'project'] }, leave(){}, enter(){}, }, { name: 'entry', once(){} } ], views: [{ namespace: 'home', beforeEnter(data) { preloader.classList.add('hide'); } }] }); const preloader = document.querySelector(".preloader");
HTML代码
<div class="preloader"> <h1 class="fs-header-1 fw-demi preloader__text--content">H E N L O</h1> </div>
CSS代码
.preloader { position: fixed; transform: translateY(0); background-color: var(--clr-neutral-900); height: 100vh; width: 100%; z-index: 2; overflow: hidden; display: flex; justify-content: center; align-items: center; transition: transform .7s cubic-bezier(0.7, 0, 0.3, 1); &.hide{ transform: translateY(-100%); } &__text--content { overflow: hidden; display: block; position: absolute; span { transition: transform 1s cubic-bezier(0.7, 0, 0.3, 1); display: inline-block; position: relative; color: var(--clr-neutral-100); transform: translateY(100%); } span.fade { transform: translateY(0%); } } } .entry-once .preloader { transform: translateY(0%); } .entry-once-active, .entry-once-active .preloader { transition: transform .7s cubic-bezier(0.7, 0, 0.3, 1) 1.3s; } .entry-once-to .preloader { transform: translateY(100%); } .transition { position: fixed; width: 100%; height: 100%; top: 0; left: 0; background-color: var(--clr-neutral-900); display: flex; align-items: center; justify-content: center; transform: translateY(-100%); z-index: 1; } .cover-leave-active, .cover-enter-active, .cover-leave-active .transition, .cover-enter-active .transition { transition: transform .7s cubic-bezier(0.7, 0, 0.3, 1); } .cover-leave .transition { transform: translateY(-100%); } .cover-leave-to .transition { transform: translateY(0); } .cover-enter .transition { transform: translateY(0); } .cover-enter-to .transition { transform: translateY(100%); }
问题分析
- 入场动画仅首次执行:原
entry过渡的once()方法只在页面首次加载时触发,从其他页面返回首页时不会重新初始化动画。 - 动画状态未重置:返回首页时,preloader的
hide类未移除、字符的fade类未清除,导致动画无法重新触发。 - 过渡逻辑冲突:
beforeEnter中直接添加hide类,强制隐藏preloader,和入场动画执行逻辑冲突引发黑屏。
修复方案
修改后的JS代码
// 封装入场动画逻辑,支持重复调用 function initEntryAnimation() { const text = document.querySelector(".preloader__text--content"); const strText = text.textContent; const splitText = strText.split(""); // 重置文本结构与字符状态 text.textContent = ""; text.innerHTML = splitText.map(char => `<span>${char}</span>`).join(''); let char = 0; const timer = setInterval(onTick, 50); function onTick(){ const span = text.querySelectorAll('span')[char]; span.classList.add('fade'); char++; if(char === splitText.length){ clearInterval(timer); setTimeout(() => { preloader.classList.add('hide'); }, 1500); } } } barba.use(barbaCss); // 全局钩子:进入新页面时自动滚动到顶部 barba.hooks.enter(() => { window.scrollTo(0, 0); }); barba.init({ transitions: [ { name: 'cover', to:{ namespace: ['project'] }, leave() {}, enter() {} }, { name: 'entry', to:{ namespace: ['home'] }, // 进入首页时重置并执行动画 enter() { const preloader = document.querySelector(".preloader"); preloader.classList.remove('hide'); // 清除字符的fade类,重置动画状态 document.querySelectorAll('.preloader__text--content span').forEach(span => { span.classList.remove('fade'); }); initEntryAnimation(); }, // 首次加载时执行动画 once() { initEntryAnimation(); } } ], views: [{ namespace: 'home', // 移除强制隐藏preloader的逻辑 beforeEnter(data) {} }] }); const preloader = document.querySelector(".preloader");
调整后的CSS(移除冲突样式)
/* 移除Barba自动生成的entry-once相关样式,改用JS控制动画 */ /* .entry-once .preloader { transform: translateY(0%); } .entry-once-active, .entry-once-active .preloader { transition: transform .7s cubic-bezier(0.7, 0, 0.3, 1) 1.3s; } .entry-once-to .preloader { transform: translateY(100%); } */
修复说明
- 复用动画逻辑:将入场动画封装成函数,首次加载和返回首页时均可调用。
- 重置状态:进入首页前清除preloader的
hide类和字符的fade类,确保动画能从头执行。 - 拆分过渡规则:让
cover过渡仅针对跳转到项目页的场景,entry过渡专门处理进入首页的场景,避免过渡冲突。 - 移除强制隐藏:删除
beforeEnter中直接隐藏preloader的代码,让动画自然完成后再隐藏。
内容的提问来源于stack exchange,提问作者dzm11
相关产品推荐
相关产品推荐

