Files

732 lines
24 KiB
JavaScript
Raw Permalink 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.

// 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"
});
}