
本文介绍如何通过 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,页面将瞬间呈现最终状态——真正实现「单次加载、全站生效」的流畅体验。










