732 lines
24 KiB
JavaScript
732 lines
24 KiB
JavaScript
|
|
// GSAP动画配置文件
|
|||
|
|
// 确保在DOM加载完成后执行动画
|
|||
|
|
|
|||
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|||
|
|
// 检查GSAP是否已加载
|
|||
|
|
if (typeof gsap === 'undefined') {
|
|||
|
|
console.warn('GSAP library is not loaded. Please include GSAP before this script.');
|
|||
|
|
// 如果GSAP未加载,确保所有元素可见
|
|||
|
|
const allElements = document.querySelectorAll('.navbar, .contact-buttons .btn, .skill-category, .contact-item, .other-experience, .modern-project-showcase');
|
|||
|
|
allElements.forEach(el => {
|
|||
|
|
if (el) {
|
|||
|
|
el.style.opacity = '1';
|
|||
|
|
el.style.visibility = 'visible';
|
|||
|
|
el.style.transform = '';
|
|||
|
|
console.log(`Made ${el.className} visible (GSAP fallback)`);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
console.log('GSAP loaded successfully, initializing animations...');
|
|||
|
|
|
|||
|
|
// ===== 页面加载动画 =====
|
|||
|
|
function initLoadingAnimations() {
|
|||
|
|
// 隐藏加载器的动画
|
|||
|
|
gsap.to("#loader", {
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.5,
|
|||
|
|
delay: 1,
|
|||
|
|
onComplete: function() {
|
|||
|
|
document.getElementById('loader').style.display = 'none';
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 导航栏动画
|
|||
|
|
// 首先确保导航栏存在
|
|||
|
|
const navbarElement = document.querySelector(".navbar");
|
|||
|
|
if (navbarElement) {
|
|||
|
|
gsap.from(".navbar", {
|
|||
|
|
y: -100,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.8,
|
|||
|
|
delay: 1.2,
|
|||
|
|
ease: "back.out(1.7)"
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
console.warn('Navbar element not found for animation');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 首页英雄区域动画 =====
|
|||
|
|
function initHeroAnimations() {
|
|||
|
|
// 确保元素初始可见,然后应用动画
|
|||
|
|
gsap.set([".hero-avatar", ".hero h1", ".hero .subtitle", ".hero .description", ".contact-buttons .btn"], {
|
|||
|
|
clearProps: "all"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const tl = gsap.timeline({ delay: 1.5 });
|
|||
|
|
|
|||
|
|
tl.from(".hero-avatar", {
|
|||
|
|
scale: 0,
|
|||
|
|
rotation: 360,
|
|||
|
|
duration: 1,
|
|||
|
|
ease: "back.out(1.7)"
|
|||
|
|
})
|
|||
|
|
.from(".hero h1", {
|
|||
|
|
y: 50,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.8,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
}, "-=0.5")
|
|||
|
|
.from(".hero .subtitle", {
|
|||
|
|
y: 30,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.6,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
}, "-=0.3")
|
|||
|
|
.from(".hero .description", {
|
|||
|
|
y: 30,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.6,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
}, "-=0.2")
|
|||
|
|
.from(".contact-buttons .btn", {
|
|||
|
|
y: 30,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.5,
|
|||
|
|
stagger: 0.1,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
}, "-=0.2");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 滚动触发动画 =====
|
|||
|
|
function initScrollAnimations() {
|
|||
|
|
// 注册ScrollTrigger插件
|
|||
|
|
if (typeof ScrollTrigger !== 'undefined') {
|
|||
|
|
gsap.registerPlugin(ScrollTrigger);
|
|||
|
|
} else {
|
|||
|
|
console.warn('ScrollTrigger plugin not found. Elements will be visible immediately.');
|
|||
|
|
// 如果ScrollTrigger不可用,确保所有元素可见
|
|||
|
|
gsap.set([".skill-category", ".contact-item", ".other-experience", ".modern-project-showcase"], {
|
|||
|
|
opacity: 1,
|
|||
|
|
y: 0,
|
|||
|
|
x: 0
|
|||
|
|
});
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 基本资料部分动画
|
|||
|
|
gsap.from("#basic-info .section-title", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: "#basic-info",
|
|||
|
|
start: "top 80%",
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
y: 50,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.8,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
gsap.from("#basic-info .project-card", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: "#basic-info",
|
|||
|
|
start: "top 70%",
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
y: 80,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 1,
|
|||
|
|
delay: 0.2,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
gsap.from("#basic-info .education-item", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: "#basic-info .education-item",
|
|||
|
|
start: "top 80%",
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
x: -80,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.8,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 技能卡片动画
|
|||
|
|
gsap.from("#skills .section-title", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: "#skills",
|
|||
|
|
start: "top 80%",
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
y: 50,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.8,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
gsap.to(".skill-category", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: "#skills",
|
|||
|
|
start: "top 70%",
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
opacity: 1,
|
|||
|
|
duration: 2,
|
|||
|
|
scale: 1,
|
|||
|
|
delay: 0.5,
|
|||
|
|
ease: "cire.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 项目展示动画
|
|||
|
|
gsap.from("#experience .section-title", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: "#experience",
|
|||
|
|
start: "top 80%",
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
y: 50,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.8,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 只为可见的项目卡片设置动画
|
|||
|
|
gsap.from("#industrial-design-content .modern-project-showcase", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: "#experience",
|
|||
|
|
start: "top 70%",
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
x: -100,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 1.2,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 为其他标签的项目卡片设置初始可见状态
|
|||
|
|
gsap.set("#machining-content .modern-project-showcase, #automation-content .modern-project-showcase, #non-standard-content .modern-project-showcase", {
|
|||
|
|
opacity: 1,
|
|||
|
|
x: 0
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 实习经历标签动画
|
|||
|
|
gsap.from(".experience-tab-btn", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: ".experience-tabs",
|
|||
|
|
start: "top 80%",
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
y: 30,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.6,
|
|||
|
|
stagger: 0.1,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
gsap.from(".placeholder-card", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: ".experience-tab-content",
|
|||
|
|
start: "top 70%",
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
y: 50,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.8,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 个人总结动画 - 极宽松触发条件,适应所有标签页面高度
|
|||
|
|
gsap.from("#summary .section-title", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: "#summary",
|
|||
|
|
start: "top 50%", // 极宽松触发阈值,页面滚动即触发
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
y: 50,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.8,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
gsap.from("#summary .summary-content", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: "#summary",
|
|||
|
|
start: "top 50%", // 极宽松触发阈值,页面滚动即触发
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
y: 30,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 1,
|
|||
|
|
delay: 0.2,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 联系信息动画 - 极宽松触发条件,适应所有标签页面高度
|
|||
|
|
gsap.from("#contact .section-title", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: "#contact",
|
|||
|
|
start: "top 100%", // 极宽松触发阈值,页面滚动即触发
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
y: 50,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.8,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
gsap.from(".contact-item", {
|
|||
|
|
scrollTrigger: {
|
|||
|
|
trigger: "#contact",
|
|||
|
|
start: "top 100%", // 极宽松触发阈值,页面滚动即触发
|
|||
|
|
toggleActions: "play none none reverse"
|
|||
|
|
},
|
|||
|
|
y: 50,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.6,
|
|||
|
|
stagger: 0.15,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 悬停交互动画 =====
|
|||
|
|
function initHoverAnimations() {
|
|||
|
|
// 项目卡片悬停动画
|
|||
|
|
const projectCard = document.querySelector('.modern-project-showcase');
|
|||
|
|
if (projectCard) {
|
|||
|
|
projectCard.addEventListener('mouseenter', function() {
|
|||
|
|
gsap.to(this, {
|
|||
|
|
y: -15,
|
|||
|
|
scale: 1.02,
|
|||
|
|
duration: 0.3,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
projectCard.addEventListener('mouseleave', function() {
|
|||
|
|
gsap.to(this, {
|
|||
|
|
y: 0,
|
|||
|
|
scale: 1,
|
|||
|
|
duration: 0.3,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 技能卡片悬停动画
|
|||
|
|
document.querySelectorAll('.skill-category').forEach(card => {
|
|||
|
|
card.addEventListener('mouseenter', function() {
|
|||
|
|
gsap.to(this, {
|
|||
|
|
y: -8,
|
|||
|
|
scale: 1.01,
|
|||
|
|
duration: 0.3,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
card.addEventListener('mouseleave', function() {
|
|||
|
|
gsap.to(this, {
|
|||
|
|
y: 0,
|
|||
|
|
scale: 1,
|
|||
|
|
duration: 0.3,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 弹窗动画增强 =====
|
|||
|
|
function initModalAnimations() {
|
|||
|
|
// 替换原有的职责弹窗动画
|
|||
|
|
window.openResponsibilitiesModalGSAP = function() {
|
|||
|
|
const modal = document.getElementById('responsibilitiesModal');
|
|||
|
|
const content = modal.querySelector('.responsibilities-modal-content');
|
|||
|
|
|
|||
|
|
modal.style.display = 'block';
|
|||
|
|
document.body.style.overflow = 'hidden';
|
|||
|
|
|
|||
|
|
// GSAP弹窗动画
|
|||
|
|
gsap.fromTo(modal,
|
|||
|
|
{ opacity: 0 },
|
|||
|
|
{ opacity: 1, duration: 0.3 }
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
gsap.fromTo(content,
|
|||
|
|
{ x: '-100%', opacity: 0 },
|
|||
|
|
{ x: '0%', opacity: 1, duration: 0.4, ease: "power2.out" }
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
window.closeResponsibilitiesModalGSAP = function() {
|
|||
|
|
const modal = document.getElementById('responsibilitiesModal');
|
|||
|
|
const content = modal.querySelector('.responsibilities-modal-content');
|
|||
|
|
|
|||
|
|
// GSAP关闭动画
|
|||
|
|
gsap.to(content, {
|
|||
|
|
x: '100%',
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.4,
|
|||
|
|
ease: "power2.in",
|
|||
|
|
onComplete: function() {
|
|||
|
|
modal.style.display = 'none';
|
|||
|
|
document.body.style.overflow = 'auto';
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
gsap.to(modal, {
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.3,
|
|||
|
|
delay: 0.1
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 智能手表项目弹窗动画
|
|||
|
|
window.openWatchProjectModalGSAP = function() {
|
|||
|
|
const modal = document.getElementById('watchProjectModal');
|
|||
|
|
const content = modal.querySelector('.responsibilities-modal-content');
|
|||
|
|
|
|||
|
|
modal.style.display = 'block';
|
|||
|
|
document.body.style.overflow = 'hidden';
|
|||
|
|
|
|||
|
|
// GSAP弹窗动画
|
|||
|
|
gsap.fromTo(modal,
|
|||
|
|
{ opacity: 0 },
|
|||
|
|
{ opacity: 1, duration: 0.3 }
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
gsap.fromTo(content,
|
|||
|
|
{ x: '-100%', opacity: 0 },
|
|||
|
|
{ x: '0%', opacity: 1, duration: 0.4, ease: "power2.out" }
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
window.closeWatchProjectModalGSAP = function() {
|
|||
|
|
const modal = document.getElementById('watchProjectModal');
|
|||
|
|
const content = modal.querySelector('.responsibilities-modal-content');
|
|||
|
|
|
|||
|
|
// GSAP关闭动画
|
|||
|
|
gsap.to(content, {
|
|||
|
|
x: '100%',
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.4,
|
|||
|
|
ease: "power2.in",
|
|||
|
|
onComplete: function() {
|
|||
|
|
modal.style.display = 'none';
|
|||
|
|
document.body.style.overflow = 'auto';
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
gsap.to(modal, {
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.3,
|
|||
|
|
delay: 0.1
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 机械加工工艺项目弹窗动画 =====
|
|||
|
|
function initMachiningProjectModalAnimations() {
|
|||
|
|
window.openMachiningProjectModalGSAP = function() {
|
|||
|
|
const modal = document.getElementById('machiningProjectModal');
|
|||
|
|
if (!modal) return;
|
|||
|
|
|
|||
|
|
modal.style.display = 'flex';
|
|||
|
|
document.body.style.overflow = 'hidden';
|
|||
|
|
|
|||
|
|
const modalContent = modal.querySelector('.responsibilities-modal-content');
|
|||
|
|
|
|||
|
|
// 重置初始状态
|
|||
|
|
gsap.set(modal, { opacity: 0 });
|
|||
|
|
gsap.set(modalContent, { x: '-100%', opacity: 0 });
|
|||
|
|
|
|||
|
|
// 弹窗背景淡入
|
|||
|
|
gsap.to(modal, {
|
|||
|
|
opacity: 1,
|
|||
|
|
duration: 0.3,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 内容区域从左侧滑入
|
|||
|
|
gsap.to(modalContent, {
|
|||
|
|
x: '0%',
|
|||
|
|
opacity: 1,
|
|||
|
|
duration: 0.5,
|
|||
|
|
delay: 0.1,
|
|||
|
|
ease: "power3.out"
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
window.closeMachiningProjectModalGSAP = function() {
|
|||
|
|
const modal = document.getElementById('machiningProjectModal');
|
|||
|
|
if (!modal) return;
|
|||
|
|
|
|||
|
|
const modalContent = modal.querySelector('.responsibilities-modal-content');
|
|||
|
|
|
|||
|
|
// 内容区域向右侧滑出
|
|||
|
|
gsap.to(modalContent, {
|
|||
|
|
x: '100%',
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.4,
|
|||
|
|
ease: "power2.in",
|
|||
|
|
onComplete: function() {
|
|||
|
|
modal.style.display = 'none';
|
|||
|
|
document.body.style.overflow = 'auto';
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
gsap.to(modal, {
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.3,
|
|||
|
|
delay: 0.1
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 自动化控制项目弹窗动画 =====
|
|||
|
|
function initAutomationProjectModalAnimations() {
|
|||
|
|
window.openAutomationProjectModalGSAP = function() {
|
|||
|
|
const modal = document.getElementById('automationProjectModal');
|
|||
|
|
if (!modal) return;
|
|||
|
|
|
|||
|
|
modal.style.display = 'flex';
|
|||
|
|
document.body.style.overflow = 'hidden';
|
|||
|
|
|
|||
|
|
const modalContent = modal.querySelector('.responsibilities-modal-content');
|
|||
|
|
|
|||
|
|
// 重置初始状态
|
|||
|
|
gsap.set(modal, { opacity: 0 });
|
|||
|
|
gsap.set(modalContent, { x: '-100%', opacity: 0 });
|
|||
|
|
|
|||
|
|
// 弹窗背景淡入
|
|||
|
|
gsap.to(modal, {
|
|||
|
|
opacity: 1,
|
|||
|
|
duration: 0.3,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 内容区域从左侧滑入
|
|||
|
|
gsap.to(modalContent, {
|
|||
|
|
x: '0%',
|
|||
|
|
opacity: 1,
|
|||
|
|
duration: 0.5,
|
|||
|
|
delay: 0.1,
|
|||
|
|
ease: "power3.out"
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
window.closeAutomationProjectModalGSAP = function() {
|
|||
|
|
const modal = document.getElementById('automationProjectModal');
|
|||
|
|
if (!modal) return;
|
|||
|
|
|
|||
|
|
const modalContent = modal.querySelector('.responsibilities-modal-content');
|
|||
|
|
|
|||
|
|
// 内容区域向右侧滑出
|
|||
|
|
gsap.to(modalContent, {
|
|||
|
|
x: '100%',
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.4,
|
|||
|
|
ease: "power2.in",
|
|||
|
|
onComplete: function() {
|
|||
|
|
modal.style.display = 'none';
|
|||
|
|
document.body.style.overflow = 'auto';
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
gsap.to(modal, {
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.3,
|
|||
|
|
delay: 0.1
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 非标自动化项目弹窗动画 =====
|
|||
|
|
function initNonStandardProjectModalAnimations() {
|
|||
|
|
window.openNonStandardProjectModalGSAP = function() {
|
|||
|
|
const modal = document.getElementById('nonStandardProjectModal');
|
|||
|
|
if (!modal) return;
|
|||
|
|
|
|||
|
|
modal.style.display = 'flex';
|
|||
|
|
document.body.style.overflow = 'hidden';
|
|||
|
|
|
|||
|
|
const modalContent = modal.querySelector('.responsibilities-modal-content');
|
|||
|
|
|
|||
|
|
// 重置初始状态
|
|||
|
|
gsap.set(modal, { opacity: 0 });
|
|||
|
|
gsap.set(modalContent, { x: '-100%', opacity: 0 });
|
|||
|
|
|
|||
|
|
// 弹窗背景淡入
|
|||
|
|
gsap.to(modal, {
|
|||
|
|
opacity: 1,
|
|||
|
|
duration: 0.3,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 内容区域从左侧滑入
|
|||
|
|
gsap.to(modalContent, {
|
|||
|
|
x: '0%',
|
|||
|
|
opacity: 1,
|
|||
|
|
duration: 0.5,
|
|||
|
|
delay: 0.1,
|
|||
|
|
ease: "power3.out"
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
window.closeNonStandardProjectModalGSAP = function() {
|
|||
|
|
const modal = document.getElementById('nonStandardProjectModal');
|
|||
|
|
if (!modal) return;
|
|||
|
|
|
|||
|
|
const modalContent = modal.querySelector('.responsibilities-modal-content');
|
|||
|
|
|
|||
|
|
// 内容区域向右侧滑出
|
|||
|
|
gsap.to(modalContent, {
|
|||
|
|
x: '100%',
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.4,
|
|||
|
|
ease: "power2.in",
|
|||
|
|
onComplete: function() {
|
|||
|
|
modal.style.display = 'none';
|
|||
|
|
document.body.style.overflow = 'auto';
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
gsap.to(modal, {
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.3,
|
|||
|
|
delay: 0.1
|
|||
|
|
});
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 粒子背景动画增强 =====
|
|||
|
|
function initParticleAnimations() {
|
|||
|
|
// 可以在这里添加与粒子背景的GSAP交互
|
|||
|
|
// 例如:鼠标移动时的粒子响应动画
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 返回顶部按钮动画管理 =====
|
|||
|
|
function initScrollTopButtonAnimation() {
|
|||
|
|
let scrollTopAnimation = null;
|
|||
|
|
const scrollTopButton = document.getElementById('scrollTop');
|
|||
|
|
|
|||
|
|
if (!scrollTopButton) return;
|
|||
|
|
|
|||
|
|
// 全局函数供外部调用
|
|||
|
|
window.startScrollTopAnimation = function() {
|
|||
|
|
if (!scrollTopAnimation) {
|
|||
|
|
scrollTopAnimation = gsap.to(scrollTopButton, {
|
|||
|
|
y: -10,
|
|||
|
|
duration: 1.5,
|
|||
|
|
repeat: -1,
|
|||
|
|
yoyo: true,
|
|||
|
|
ease: "power2.inOut"
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
window.stopScrollTopAnimation = function() {
|
|||
|
|
if (scrollTopAnimation) {
|
|||
|
|
scrollTopAnimation.kill();
|
|||
|
|
gsap.set(scrollTopButton, { y: 0 });
|
|||
|
|
scrollTopAnimation = null;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 统一的元素可见性确保机制 =====
|
|||
|
|
function ensureElementsVisible() {
|
|||
|
|
// 确保关键元素始终可见,防止动画失败导致元素消失
|
|||
|
|
const criticalElements = [
|
|||
|
|
'.navbar', // 导航栏
|
|||
|
|
'.contact-buttons .btn', // 首页按钮
|
|||
|
|
'.skill-category', // 技能卡片
|
|||
|
|
'.contact-item', // 联系方式
|
|||
|
|
'.experience-tab-btn', // 实习经历标签
|
|||
|
|
'.modern-project-showcase' // 项目展示
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
criticalElements.forEach(selector => {
|
|||
|
|
const elements = document.querySelectorAll(selector);
|
|||
|
|
elements.forEach(el => {
|
|||
|
|
if (el) {
|
|||
|
|
// 检查元素是否可能被隐藏
|
|||
|
|
const computedStyle = window.getComputedStyle(el);
|
|||
|
|
const isHidden = el.style.opacity === '0' ||
|
|||
|
|
el.style.visibility === 'hidden' ||
|
|||
|
|
computedStyle.opacity === '0' ||
|
|||
|
|
computedStyle.visibility === 'hidden';
|
|||
|
|
|
|||
|
|
if (isHidden) {
|
|||
|
|
console.log(`Making ${selector} visible as fallback`);
|
|||
|
|
if (typeof gsap !== 'undefined') {
|
|||
|
|
// 优先使用GSAP设置
|
|||
|
|
gsap.set(el, { opacity: 1, visibility: 'visible', y: 0, x: 0 });
|
|||
|
|
} else {
|
|||
|
|
// 回退到原生CSS
|
|||
|
|
el.style.opacity = '1';
|
|||
|
|
el.style.visibility = 'visible';
|
|||
|
|
el.style.transform = '';
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===== 初始化所有动画 =====
|
|||
|
|
function initAllAnimations() {
|
|||
|
|
try {
|
|||
|
|
initLoadingAnimations();
|
|||
|
|
initHeroAnimations();
|
|||
|
|
initScrollAnimations();
|
|||
|
|
initHoverAnimations();
|
|||
|
|
initModalAnimations();
|
|||
|
|
initMachiningProjectModalAnimations();
|
|||
|
|
initAutomationProjectModalAnimations();
|
|||
|
|
initNonStandardProjectModalAnimations();
|
|||
|
|
initParticleAnimations();
|
|||
|
|
initScrollTopButtonAnimation();
|
|||
|
|
|
|||
|
|
// 延迟检查元素可见性
|
|||
|
|
setTimeout(ensureElementsVisible, 2000);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('GSAP animation initialization failed:', error);
|
|||
|
|
// 如果动画初始化失败,确保所有元素可见
|
|||
|
|
ensureElementsVisible();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 启动动画系统
|
|||
|
|
initAllAnimations();
|
|||
|
|
|
|||
|
|
// 暴露一些函数到全局作用域,以便HTML中调用
|
|||
|
|
window.gsapAnimations = {
|
|||
|
|
openModal: window.openResponsibilitiesModalGSAP,
|
|||
|
|
closeModal: window.closeResponsibilitiesModalGSAP,
|
|||
|
|
openWatchModal: window.openWatchProjectModalGSAP,
|
|||
|
|
closeWatchModal: window.closeWatchProjectModalGSAP
|
|||
|
|
};
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// ===== 工具函数 =====
|
|||
|
|
function createTextAnimation(selector, options = {}) {
|
|||
|
|
const defaults = {
|
|||
|
|
y: 30,
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.6,
|
|||
|
|
stagger: 0.1,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const settings = { ...defaults, ...options };
|
|||
|
|
|
|||
|
|
return gsap.from(selector, settings);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function createFadeInAnimation(selector, direction = 'up', distance = 50) {
|
|||
|
|
const transforms = {
|
|||
|
|
up: { y: distance },
|
|||
|
|
down: { y: -distance },
|
|||
|
|
left: { x: distance },
|
|||
|
|
right: { x: -distance }
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return gsap.from(selector, {
|
|||
|
|
...transforms[direction],
|
|||
|
|
opacity: 0,
|
|||
|
|
duration: 0.8,
|
|||
|
|
ease: "power2.out"
|
|||
|
|
});
|
|||
|
|
}
|