Files
n8n_Demo/web_frontend/web_result/js/page-loader.js

387 lines
15 KiB
JavaScript
Raw Normal View History

// 页面加载动画组件
(function() {
// 创建加载器HTML结构
function createLoader() {
const loaderHTML = `
<div id="page-loader" class="fixed inset-0 bg-white z-[9999] flex items-center justify-center">
<!-- 背景动画 -->
<div class="absolute inset-0 overflow-hidden">
<!-- 渐变背景 -->
<div class="absolute inset-0 bg-gradient-to-br from-blue-50 via-purple-50 to-emerald-50"></div>
<!-- 浮动粒子 -->
<div class="floating-particles">
${Array.from({length: 12}).map((_, i) => `
<div class="particle particle-${i + 1}"></div>
`).join('')}
</div>
<!-- 几何图形 -->
<div class="geometric-shapes">
<div class="shape shape-1"></div>
<div class="shape shape-2"></div>
<div class="shape shape-3"></div>
</div>
</div>
<!-- 主加载内容 -->
<div class="relative z-10 text-center">
<!-- Logo区域 -->
<div class="mb-8">
<div class="w-20 h-20 mx-auto mb-4 relative">
<!-- 旋转的环 -->
<div class="absolute inset-0 border-4 border-transparent border-t-emerald-500 border-r-blue-500 rounded-full animate-spin"></div>
<div class="absolute inset-2 border-4 border-transparent border-b-purple-500 border-l-pink-500 rounded-full animate-spin-reverse"></div>
<!-- 中心图标 -->
<div class="absolute inset-0 flex items-center justify-center">
<div class="w-8 h-8 bg-gradient-to-br from-emerald-400 to-blue-500 rounded-lg flex items-center justify-center text-white font-bold text-sm animate-pulse">
</div>
</div>
</div>
<!-- 品牌名称 -->
<h1 class="text-2xl font-bold text-gray-800 mb-2 animate-fade-in">
长三角国际新能源汽车博览会
</h1>
<p class="text-gray-600 animate-fade-in-delay">
智行未来绿动长三角
</p>
</div>
<!-- 进度条 -->
<div class="w-64 mx-auto mb-6">
<div class="bg-gray-200 rounded-full h-2 overflow-hidden">
<div id="loading-progress" class="h-full bg-gradient-to-r from-emerald-400 to-blue-500 rounded-full transition-all duration-300 ease-out" style="width: 0%"></div>
</div>
<div class="flex justify-between text-xs text-gray-500 mt-2">
<span>加载中</span>
<span id="loading-percentage">0%</span>
</div>
</div>
<!-- 加载状态文字 -->
<div class="text-sm text-gray-500">
<span id="loading-text">正在准备展会信息</span>
<span class="loading-dots">
<span class="dot">.</span>
<span class="dot">.</span>
<span class="dot">.</span>
</span>
</div>
</div>
</div>
`;
// 将加载器插入到 body 的最前面确保body存在
if (document.body) {
document.body.insertAdjacentHTML('afterbegin', loaderHTML);
} else {
// 如果body不存在等待DOM加载完成
document.addEventListener('DOMContentLoaded', function() {
if (document.body && !document.getElementById('page-loader')) {
document.body.insertAdjacentHTML('afterbegin', loaderHTML);
}
});
}
}
// 添加样式
function addStyles() {
const style = document.createElement('style');
style.textContent = `
/* 基础动画定义 */
@keyframes spin-reverse {
from { transform: rotate(0deg); }
to { transform: rotate(-360deg); }
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes fade-in-delay {
from { opacity: 0; transform: translateY(15px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes float {
0%, 100% { transform: translateY(0px) rotate(0deg); }
25% { transform: translateY(-10px) rotate(90deg); }
50% { transform: translateY(-5px) rotate(180deg); }
75% { transform: translateY(-15px) rotate(270deg); }
}
@keyframes dot-blink {
0%, 20% { opacity: 0; }
50% { opacity: 1; }
100% { opacity: 0; }
}
@keyframes shape-float {
0%, 100% { transform: translateY(0px) translateX(0px) rotate(0deg); }
33% { transform: translateY(-20px) translateX(10px) rotate(120deg); }
66% { transform: translateY(10px) translateX(-10px) rotate(240deg); }
}
@keyframes particle-drift {
0% { transform: translateY(100vh) translateX(0px) rotate(0deg); opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { transform: translateY(-100px) translateX(50px) rotate(360deg); opacity: 0; }
}
/* 应用动画类 */
.animate-spin-reverse {
animation: spin-reverse 2s linear infinite;
}
.animate-fade-in {
animation: fade-in 1s ease-out forwards;
}
.animate-fade-in-delay {
animation: fade-in-delay 1s ease-out 0.3s forwards;
opacity: 0;
}
/* 加载点动画 */
.loading-dots {
display: inline-block;
}
.loading-dots .dot {
animation: dot-blink 1.4s infinite;
}
.loading-dots .dot:nth-child(2) {
animation-delay: 0.2s;
}
.loading-dots .dot:nth-child(3) {
animation-delay: 0.4s;
}
/* 浮动粒子 */
.floating-particles {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
}
.particle {
position: absolute;
width: 6px;
height: 6px;
border-radius: 50%;
animation: particle-drift 8s infinite linear;
}
.particle-1 { background: rgba(16, 185, 129, 0.6); left: 10%; animation-delay: 0s; animation-duration: 8s; }
.particle-2 { background: rgba(59, 130, 246, 0.6); left: 20%; animation-delay: 1s; animation-duration: 10s; }
.particle-3 { background: rgba(168, 85, 247, 0.6); left: 30%; animation-delay: 2s; animation-duration: 9s; }
.particle-4 { background: rgba(236, 72, 153, 0.6); left: 40%; animation-delay: 3s; animation-duration: 11s; }
.particle-5 { background: rgba(245, 158, 11, 0.6); left: 50%; animation-delay: 4s; animation-duration: 7s; }
.particle-6 { background: rgba(239, 68, 68, 0.6); left: 60%; animation-delay: 5s; animation-duration: 9s; }
.particle-7 { background: rgba(16, 185, 129, 0.6); left: 70%; animation-delay: 6s; animation-duration: 8s; }
.particle-8 { background: rgba(59, 130, 246, 0.6); left: 80%; animation-delay: 7s; animation-duration: 10s; }
.particle-9 { background: rgba(168, 85, 247, 0.6); left: 90%; animation-delay: 1.5s; animation-duration: 9s; }
.particle-10 { background: rgba(236, 72, 153, 0.6); left: 15%; animation-delay: 2.5s; animation-duration: 11s; }
.particle-11 { background: rgba(245, 158, 11, 0.6); left: 25%; animation-delay: 3.5s; animation-duration: 7s; }
.particle-12 { background: rgba(239, 68, 68, 0.6); left: 85%; animation-delay: 4.5s; animation-duration: 8s; }
/* 几何图形 */
.geometric-shapes {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
}
.shape {
position: absolute;
border-radius: 12px;
animation: shape-float 6s ease-in-out infinite;
}
.shape-1 {
top: 20%;
left: 10%;
width: 40px;
height: 40px;
background: linear-gradient(45deg, rgba(16, 185, 129, 0.1), rgba(59, 130, 246, 0.1));
animation-delay: 0s;
}
.shape-2 {
top: 60%;
right: 15%;
width: 60px;
height: 60px;
background: linear-gradient(135deg, rgba(168, 85, 247, 0.1), rgba(236, 72, 153, 0.1));
border-radius: 50%;
animation-delay: 2s;
}
.shape-3 {
bottom: 30%;
left: 20%;
width: 32px;
height: 32px;
background: linear-gradient(225deg, rgba(245, 158, 11, 0.1), rgba(239, 68, 68, 0.1));
animation-delay: 4s;
}
/* 加载器隐藏动画 */
#page-loader.fade-out {
animation: fadeOutLoader 0.8s ease-in-out forwards;
}
@keyframes fadeOutLoader {
0% {
opacity: 1;
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(1.05);
}
}
/* 防止页面滚动 */
body.loading {
overflow: hidden;
}
`;
document.head.appendChild(style);
}
// 更新加载进度
function updateProgress(percentage, text) {
const progressBar = document.getElementById('loading-progress');
const percentageText = document.getElementById('loading-percentage');
const loadingText = document.getElementById('loading-text');
if (progressBar) {
progressBar.style.width = percentage + '%';
}
if (percentageText) {
percentageText.textContent = percentage + '%';
}
if (loadingText && text) {
loadingText.textContent = text;
}
}
// 模拟加载过程
function simulateLoading() {
const loadingSteps = [
{ progress: 0, text: '正在准备展会信息', delay: 100 },
{ progress: 15, text: '加载导航组件', delay: 200 },
{ progress: 30, text: '获取展会数据', delay: 300 },
{ progress: 45, text: '渲染页面布局', delay: 250 },
{ progress: 60, text: '加载图片资源', delay: 400 },
{ progress: 75, text: '初始化交互功能', delay: 200 },
{ progress: 85, text: '优化页面性能', delay: 150 },
{ progress: 95, text: '准备完成', delay: 200 },
{ progress: 100, text: '加载完成', delay: 300 }
];
let currentStep = 0;
function nextStep() {
if (currentStep < loadingSteps.length) {
const step = loadingSteps[currentStep];
updateProgress(step.progress, step.text);
currentStep++;
setTimeout(nextStep, step.delay);
} else {
// 加载完成,延迟一点时间后隐藏加载器
setTimeout(hideLoader, 500);
}
}
// 开始加载过程
setTimeout(nextStep, 300);
}
// 隐藏加载器
function hideLoader() {
const loader = document.getElementById('page-loader');
if (loader) {
loader.classList.add('fade-out');
// 动画结束后移除元素并恢复页面滚动
setTimeout(() => {
loader.remove();
document.body.classList.remove('loading');
// 触发页面加载完成事件
document.dispatchEvent(new CustomEvent('pageLoaded'));
}, 800);
}
}
// 初始化加载器
function init() {
// 确保DOM已加载
if (!document.body) {
// 如果body还不存在等待DOM加载完成
document.addEventListener('DOMContentLoaded', init);
return;
}
// 添加样式
addStyles();
// 创建加载器
createLoader();
// 禁用页面滚动
if (document.body) {
document.body.classList.add('loading');
}
// 等待页面资源加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
setTimeout(simulateLoading, 200);
});
} else {
setTimeout(simulateLoading, 200);
}
// 监听 window load 事件(所有资源包括图片都加载完成)
window.addEventListener('load', () => {
// 如果加载器仍然存在,加速完成过程
if (document.getElementById('page-loader')) {
updateProgress(100, '加载完成');
setTimeout(hideLoader, 300);
}
});
// 监听页面可见性变化(用户切换标签页时暂停动画)
document.addEventListener('visibilitychange', function() {
const loader = document.getElementById('page-loader');
if (loader) {
if (document.hidden) {
loader.style.animationPlayState = 'paused';
} else {
loader.style.animationPlayState = 'running';
}
}
});
}
// 提供外部接口
window.PageLoader = {
updateProgress,
hideLoader
};
// 初始化
init();
})();