
本文介绍如何通过 localstorage 实现跨页面的加载状态持久化,使加载动画仅在用户首次访问网站时触发一次,后续跳转至其他 html 页面(如 about.html)时自动跳过,提升用户体验。
在多页静态网站(如 index.html 和 about.html)中,若每个页面都嵌入相同的加载屏(#load)和计数逻辑,用户每次跳转都会重新触发 0% → 100% 动画——这不仅违背“一次性加载”的设计初衷,也造成不必要的性能开销与体验割裂。
根本原因在于:HTML 页面是独立加载的,javaScript 执行环境不共享,且默认无状态记忆能力。因此,必须引入客户端持久化机制来标记“加载已完成”。
✅ 推荐方案:使用 localStorage 记录加载完成状态
在 counter() 函数执行前,先检查本地存储中是否存在标记(例如 ‘loadCompleted’: ‘true’)。若存在,则直接跳过整个加载流程,并立即应用动画类;否则执行计数逻辑,并在达到 100% 后写入该标记。
以下是优化后的完整实现:
0
function counter() { const loadNo = document.getElementById('load-no'); const load = document.getElementById('load'); // ✅ 检查是否已加载完成 if (localStorage.getItem('loadCompleted') === 'true') { // 直接移除加载屏并应用动画类(模拟已完成状态) load.classList.add('loaded'); document.body.classList.add('loaded-body'); // 可选:用于全局样式控制 // 立即为关键元素添加动画类(与原逻辑一致) const evLogo = document.getElementById('ev-logo'); const navLinks = document.querySelectorAll('.nav-a'); const fbIcon = document.querySelector('.fb-icon'); const githubIcon = document.querySelector('.github-icon'); const lineH = document.querySelector('.line-h'); const lineV = document.querySelector('.line-v'); const copyrightIcon = document.querySelector('.copyright-icon'); const yearEl = document.querySelector('.year'); const nameEl = document.querySelector('.name'); const earlEl = document.querySelector('.earl-villarias'); const sloganText = document.querySelector('.slogan-text'); const sloganLines = document.querySelectorAll('.slogan-line'); if (evLogo) evLogo.style.transform = 'translate3d(0px, 0px, 0px)'; if (fbIcon) fbIcon.classList.add('fb-icon-s'); if (githubIcon) githubIcon.classList.add('github-icon-s'); if (lineH) lineH.classList.add('line-expand-h'); if (lineV) lineV.classList.add('line-expand-v'); if (copyrightIcon) copyrightIcon.classList.add('icon-year-s'); if (yearEl) yearEl.classList.add('icon-year-s'); if (nameEl) nameEl.classList.add('name-s'); if (earlEl) earlEl.classList.add('name-show'); if (sloganText) sloganText.classList.add('slogan-show'); sloganLines.forEach(el => el.classList.add('slogan-line-expand')); navLinks.forEach(link => link.classList.add('s-d')); // 隐藏加载屏(可配合 CSS transition) load.style.opacity = '0'; setTimeout(() => { load.style.display = 'none'; }, 300); return; // ✅ 提前退出,不再执行计数 } // ❌ 否则执行原始计数逻辑 const counts = setInterval(() => { const number = parseInt(loadNo.textContent) || 0; loadNo.textContent = (number + 1).toString(); if (loadNo.textContent === '100') { clearInterval(counts); localStorage.setItem('loadCompleted', 'true'); // ✅ 永久标记完成 // 执行与上方完全相同的动画类添加逻辑(复用更佳,此处为清晰展示) if (evLogo) evLogo.style.transform = 'translate3d(0px, 0px, 0px)'; if (fbIcon) fbIcon.classList.add('fb-icon-s'); if (githubIcon) githubIcon.classList.add('github-icon-s'); if (lineH) lineH.classList.add('line-expand-h'); if (lineV) lineV.classList.add('line-expand-v'); if (copyrightIcon) copyrightIcon.classList.add('icon-year-s'); if (yearEl) yearEl.classList.add('icon-year-s'); if (nameEl) nameEl.classList.add('name-s'); if (earlEl) earlEl.classList.add('name-show'); if (sloganText) sloganText.classList.add('slogan-show'); sloganLines.forEach(el => el.classList.add('slogan-line-expand')); navLinks.forEach(link => link.classList.add('s-d')); // 平滑隐藏加载屏 load.style.transition = 'opacity 0.3s ease-out'; load.style.opacity = '0'; setTimeout(() => { load.style.display = 'none'; }, 300); } }, 30); // 每30ms递增1%,全程约3秒 } // 页面加载完成后启动 document.addEventListener('domContentLoaded', counter);
? 关键注意事项:
- localStorage 是同源(origin)隔离的,确保 index.html 和 about.html 在同一协议、域名、端口下运行(如 http://localhost:5500/),否则无法共享状态;
- 若需支持「强制刷新重载」或「清除加载状态」,可增加调试按钮:localStorage.removeItem(‘loadCompleted’);
- 建议为 #load 添加 css 过渡效果(如 transition: opacity 0.3s),使隐藏更自然;
- 生产环境中,可将重复的 DOM 操作逻辑封装为函数(如 applyAnimations()),提升可维护性。
通过这一方案,用户首次访问任一页面(如 index.html)时触发完整加载动画;随后点击导航跳转至 about.html,页面将瞬间呈现最终状态——真正实现「单次加载、全站生效」的流畅体验。