Files
Agent-n8n/web_frontend/web_result/js/page-loader.js
Yep_Q 3825deb3e0 优化项目配置和页面结构
- 更新settings.local.json,移除冗余的权限设置,添加新的Playwright相关权限。
- 删除exhibition_demo_project_2025.md文档,清理不再使用的文件。
- 更新多个HTML页面,统一viewport设置,添加页面加载动画、错误处理和性能优化脚本。
- 统一使用Tailwind CSS的引入方式,提升页面加载性能。
- 增强导航组件,支持移动端菜单和返回顶部功能,改善用户体验。
2025-09-10 02:35:16 +08:00

387 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 页面加载动画组件
(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();
})();