-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.js
More file actions
178 lines (150 loc) · 5.42 KB
/
main.js
File metadata and controls
178 lines (150 loc) · 5.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// 移动端菜单切换
function toggleMenu() {
const menu = document.getElementById('mobile-menu');
menu.classList.toggle('hidden');
menu.classList.toggle('flex');
}
// 打字机效果循环
function initTypewriter() {
const lines = document.querySelectorAll('.typewriter-line');
let currentIndex = 0;
function resetAnimation() {
lines.forEach(line => {
line.style.animation = 'none';
line.offsetHeight; // 触发重排
line.style.animation = null;
});
}
// 每15秒重置一次动画,实现循环打字效果
setInterval(() => {
resetAnimation();
}, 15000);
}
// 页面加载后启动打字机循环
window.addEventListener('load', initTypewriter);
// 滚动动画
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
// 技能条动画
if (entry.target.querySelector('.skill-fill')) {
entry.target.querySelectorAll('.skill-fill').forEach(bar => {
const width = bar.getAttribute('data-width');
setTimeout(() => {
bar.style.width = width;
}, 200);
});
}
}
});
}, observerOptions);
document.querySelectorAll('.fade-in').forEach(el => {
observer.observe(el);
});
// 生成浮动粒子
function createParticles() {
const container = document.getElementById('particles');
const particleCount = 25;
for (let i = 0; i < particleCount; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
particle.style.left = Math.random() * 100 + '%';
particle.style.top = Math.random() * 100 + '%';
particle.style.animationDuration = (Math.random() * 20 + 10) + 's';
particle.style.animationDelay = Math.random() * 5 + 's';
// 随机运动
const destX = (Math.random() - 0.5) * 200;
const destY = (Math.random() - 0.5) * 200;
particle.style.transition = `transform ${Math.random() * 10 + 10}s linear`;
container.appendChild(particle);
// 动画循环
setInterval(() => {
particle.style.transform = `translate(${destX}px, ${destY}px)`;
setTimeout(() => {
particle.style.transform = 'translate(0, 0)';
}, 5000);
}, 10000);
}
}
createParticles();
// 滚轮滑动卡片 - 鼠标拖拽 + 箭头 + 分页点
function initCarousel() {
const carousel = document.getElementById('explore-carousel');
const track = carousel?.querySelector('.carousel-track');
const dots = document.querySelectorAll('#carousel-dots .carousel-dot');
const arrowLeft = document.querySelector('.carousel-arrow-left');
const arrowRight = document.querySelector('.carousel-arrow-right');
if (!carousel || !track) return;
function getCardWidth() {
const card = track.querySelector('.carousel-card');
const gap = 24;
return card ? card.offsetWidth + gap : 384;
}
let isDown = false;
let startX;
let scrollLeft;
// 鼠标拖拽
carousel.addEventListener('mousedown', (e) => {
isDown = true;
carousel.classList.add('grabbing');
startX = e.pageX - carousel.offsetLeft;
scrollLeft = carousel.scrollLeft;
});
carousel.addEventListener('mouseleave', () => {
isDown = false;
carousel.classList.remove('grabbing');
});
carousel.addEventListener('mouseup', () => {
isDown = false;
carousel.classList.remove('grabbing');
});
carousel.addEventListener('mousemove', (e) => {
if (!isDown) return;
e.preventDefault();
const x = e.pageX - carousel.offsetLeft;
const walk = (x - startX) * 1.2;
carousel.scrollLeft = scrollLeft - walk;
});
// 箭头
arrowLeft?.addEventListener('click', () => {
carousel.scrollBy({ left: -getCardWidth(), behavior: 'smooth' });
});
arrowRight?.addEventListener('click', () => {
carousel.scrollBy({ left: getCardWidth(), behavior: 'smooth' });
});
// 分页点
dots.forEach((dot, i) => {
dot.addEventListener('click', () => {
carousel.scrollTo({ left: i * getCardWidth(), behavior: 'smooth' });
});
});
// 滚动时更新激活的分页点
function updateDots() {
const cardWidth = getCardWidth();
const scrollPos = carousel.scrollLeft;
const index = Math.round(scrollPos / cardWidth);
const activeIndex = Math.min(Math.max(0, index), dots.length - 1);
dots.forEach((d, i) => d.classList.toggle('active', i === activeIndex));
}
carousel.addEventListener('scroll', updateDots);
updateDots();
}
window.addEventListener('load', initCarousel);
// 平滑滚动
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});