(∠・ω< )⌒★

546 字
3 分钟
为 Fuwari 添加开屏动画
WARNING

基于 AI 的产物,介意请慎用

一.创建开屏动画组件#

src/layouts/ 目录下创建 LoadingOverlay.astro 文件:

Terminal window
---
import { siteConfig } from "@/config";
interface Props {
enable?: boolean;
text?: string;
duration?: number;
}
const {
enable = siteConfig.preloader.enable,
text = siteConfig.preloader.text || siteConfig.title,
duration = siteConfig.preloader.duration
} = Astro.props;
---
{enable && (
<div class="preloader">
<h2 class="ml13">{text}</h2>
</div>
)}
<style is:global>
.preloader {
position: fixed;
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
background-color: var(--page-bg);
z-index: 1100;
transition: opacity 0.3s ease-in-out;
}
.ml13 {
font-size: 3.2rem;
color: var(--primary);
letter-spacing: -1px;
font-weight: 500;
text-align: center;
opacity: 0;
}
.ml13.ready {
opacity: 1;
}
.ml13 .word {
display: inline-flex;
flex-wrap: wrap;
white-space: nowrap;
}
.ml13 .letter {
display: inline-block;
line-height: 1em;
opacity: 0;
transform: translateY(25px);
filter: blur(5px);
transition: opacity 0.6s ease-out, transform 0.6s ease-out, filter 0.6s ease-out;
}
</style>
<script define:vars={{ preloaderDuration: duration }}>
function initPreloader() {
const textWrapper = document.querySelector('.ml13');
if (!textWrapper) return;
const words = textWrapper.textContent?.trim().split(' ') || [];
textWrapper.innerHTML = '';
words.forEach((word) => {
const wordSpan = document.createElement('span');
wordSpan.classList.add('word');
wordSpan.innerHTML = word.replace(/\S/g, "<span class='letter'>$&</span>");
textWrapper.appendChild(wordSpan);
textWrapper.appendChild(document.createTextNode(' '));
});
// 文字分割完成,显示容器
textWrapper.classList.add('ready');
function hidePreloader() {
const preloader = document.querySelector('.preloader');
if (preloader) {
preloader.style.opacity = '0';
setTimeout(() => {
preloader.style.display = 'none';
}, 300);
}
}
// 使用 requestAnimationFrame 确保动画流畅
const letters = document.querySelectorAll('.ml13 .letter');
// 等待浏览器渲染完成后再开始动画
requestAnimationFrame(() => {
requestAnimationFrame(() => {
// 淡入动画 - 增加初始延迟确保稳定性
letters.forEach((letter, i) => {
setTimeout(() => {
letter.style.opacity = '1';
letter.style.transform = 'translateY(0)';
letter.style.filter = 'blur(0px)';
}, 500 + i * 30);
});
// 使用配置的时长控制淡出时机
const fadeOutDelay = preloaderDuration * 0.6; // 60% 时开始淡出
setTimeout(() => {
letters.forEach((letter, i) => {
setTimeout(() => {
letter.style.opacity = '0';
letter.style.transform = 'translateY(-50px)';
letter.style.filter = 'blur(5px)';
}, i * 15);
});
// 计算最后一个字母完全淡出的时间
const lastLetterDelay = (letters.length - 1) * 15; // 最后一个字母开始淡出的延迟
const transitionDuration = 250; // CSS transition 时长 0.6s
const totalFadeOutTime = lastLetterDelay + transitionDuration;
// 等待所有文字完全淡出后再隐藏遮罩
setTimeout(hidePreloader, totalFadeOutTime);
}, fadeOutDelay);
});
});
// 页面加载完成后也隐藏(备用方案)
window.addEventListener('load', () => {
setTimeout(hidePreloader, preloaderDuration);
});
}
// 确保 DOM 完全准备好
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initPreloader);
} else {
initPreloader();
}
</script>

二.添加配置文件#

src 目录下编辑 config.ts 文件添加以下内容:

Terminal window
preloader: {
enable: true, // 启用页面加载遮罩
text: "(∠・ω< )⌒★", // 自定义显示文字,留空则使用网站标题
duration: 2000, // 遮罩显示时长(毫秒)
}
为 Fuwari 添加开屏动画
https://fuwari.vercel.app/posts/blog/add-welcome-overlay/
作者
Murasame
发布于
2026-01-10
许可协议
CC BY-NC-SA 4.0