Skip to content

Commit 3c949e8

Browse files
committed
feat: 优化首页背景格子交互
1 parent cdde9b8 commit 3c949e8

File tree

3 files changed

+80
-129
lines changed

3 files changed

+80
-129
lines changed

index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ <h1 class="slogan">赴九天 问苍穹</h1>
3535
<h3 class="title">中国载人航天</h3>
3636
<div class="top-left-light"></div>
3737
<div class="bottom-right-light"></div>
38-
<svg class="grid-overlay" viewBox="0 0 1000 1000" preserveAspectRatio="xMidYMid meet">
39-
</svg>
38+
<div class="grid-overlay" id="grid">
39+
</div>
4040
</div>
4141
<div class="page">
4242
<img class="rocket-line-draft" src="./assets/images/index/RocketLineDraft.svg" alt="火箭线稿">

scripts/index/index.js

Lines changed: 63 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -51,150 +51,90 @@ const config = {
5151
};
5252

5353
class InteractiveGrid {
54-
constructor(svgElement) {
55-
this.svg = svgElement;
56-
this.lines = [];
57-
this.mousePos = { x: 0, y: 0 };
58-
this.isThrottled = false;
54+
constructor(gridElement) {
55+
this.grid = gridElement;
56+
this.cells = [];
57+
this.rows = 7;
58+
this.cols = 12;
5959
this.setupGrid();
6060
this.setupEventListeners();
6161
}
6262

6363
setupGrid() {
64-
const rect = this.svg.getBoundingClientRect();
65-
const aspectRatio = rect.width / rect.height;
66-
this.svg.setAttribute('viewBox', `0 0 ${1000 * aspectRatio} 1000`);
67-
68-
const segments = 60; // 减少分段数量以提高性能
69-
70-
// 水平线
71-
for (let i = 0; i <= config.gridHeight; i++) {
72-
const y = (i * 1000) / config.gridHeight;
73-
for (let j = 0; j < segments; j++) {
74-
const x1 = (j * 1000 * aspectRatio) / segments;
75-
const x2 = ((j + 1) * 1000 * aspectRatio) / segments;
76-
const line = document.createElementNS("http://www.w3.org/2000/svg", "line");
77-
line.setAttribute("x1", x1.toString());
78-
line.setAttribute("y1", y.toString());
79-
line.setAttribute("x2", x2.toString());
80-
line.setAttribute("y2", y.toString());
81-
line.setAttribute("data-original-y", y.toString());
82-
line.setAttribute("data-center-x", ((x1 + x2) / 2).toString());
83-
84-
// 添加边缘渐变效果并存储基础透明度
85-
const edgeFactorY = Math.min(i / 2, (config.gridHeight - i) / 2);
86-
const opacity = Math.min(edgeFactorY, 1) * 0.15;
87-
line.setAttribute("data-base-opacity", opacity.toString());
88-
line.style.stroke = `rgba(255, 255, 255, ${opacity})`;
89-
90-
this.svg.appendChild(line);
91-
this.lines.push(line);
92-
}
93-
}
94-
95-
// 垂直线
96-
for (let i = 0; i <= config.gridWidth; i++) {
97-
const x = (i * 1000 * aspectRatio) / config.gridWidth;
98-
for (let j = 0; j < segments; j++) {
99-
const y1 = (j * 1000) / segments;
100-
const y2 = ((j + 1) * 1000) / segments;
101-
const line = document.createElementNS("http://www.w3.org/2000/svg", "line");
102-
line.setAttribute("x1", x.toString());
103-
line.setAttribute("y1", y1.toString());
104-
line.setAttribute("x2", x.toString());
105-
line.setAttribute("y2", y2.toString());
106-
line.setAttribute("data-original-x", x.toString());
107-
line.setAttribute("data-center-y", ((y1 + y2) / 2).toString());
108-
109-
// 添加边缘渐变效果并存储基础透明度
110-
const edgeFactorX = Math.min(i / 2, (config.gridWidth - i) / 2);
111-
const opacity = Math.min(edgeFactorX, 1) * 0.15;
112-
line.setAttribute("data-base-opacity", opacity.toString());
113-
line.style.stroke = `rgba(255, 255, 255, ${opacity})`;
114-
115-
this.svg.appendChild(line);
116-
this.lines.push(line);
64+
// 创建格子
65+
for (let row = 0; row < this.rows; row++) {
66+
for (let col = 0; col < this.cols; col++) {
67+
const div = document.createElement("div");
68+
div.classList.add("grid-cell");
69+
div.dataset.row = row;
70+
div.dataset.col = col;
71+
this.grid.appendChild(div);
72+
this.cells.push(div);
11773
}
11874
}
11975
}
12076

12177
setupEventListeners() {
122-
this.svg.addEventListener('mousemove', (e) => {
123-
if (this.isThrottled) return;
124-
this.isThrottled = true;
125-
126-
setTimeout(() => {
127-
this.isThrottled = false;
128-
}, config.throttleDelay);
129-
130-
const rect = this.svg.getBoundingClientRect();
131-
const aspectRatio = rect.width / rect.height;
132-
const scaleX = (1000 * aspectRatio) / rect.width;
133-
const scaleY = 1000 / rect.height;
134-
135-
this.mousePos = {
136-
x: (e.clientX - rect.left) * scaleX,
137-
y: (e.clientY - rect.top) * scaleY
138-
};
139-
140-
this.updateGrid();
78+
this.cells.forEach((cell) => {
79+
cell.addEventListener("mouseenter", () => {
80+
const row = parseInt(cell.dataset.row);
81+
const col = parseInt(cell.dataset.col);
82+
this.highlight(row, col);
83+
});
14184
});
14285

143-
this.svg.addEventListener('mouseleave', () => {
86+
this.grid.addEventListener("mouseleave", () => {
14487
this.resetGrid();
14588
});
14689
}
14790

148-
updateGrid() {
149-
const smoothstep = (min, max, value) => {
150-
const x = Math.max(0, Math.min(1, (value - min) / (max - min)));
151-
return x * x * (3 - 2 * x);
152-
};
153-
154-
this.lines.forEach(line => {
155-
let distance;
156-
const baseOpacity = parseFloat(line.getAttribute('data-base-opacity') || "0.15");
157-
158-
if (line.hasAttribute('data-original-y')) {
159-
const centerX = parseFloat(line.getAttribute('data-center-x'));
160-
const centerY = parseFloat(line.getAttribute('data-original-y'));
161-
distance = Math.sqrt(Math.pow(centerX - this.mousePos.x, 2) + Math.pow(centerY - this.mousePos.y, 2));
162-
} else {
163-
const centerX = parseFloat(line.getAttribute('data-original-x'));
164-
const centerY = parseFloat(line.getAttribute('data-center-y'));
165-
distance = Math.sqrt(Math.pow(centerX - this.mousePos.x, 2) + Math.pow(centerY - this.mousePos.y, 2));
166-
}
167-
168-
if (distance < config.mouseInfluenceRadius) {
169-
const intensity = smoothstep(0, config.mouseInfluenceRadius, config.mouseInfluenceRadius - distance);
170-
const glowStrength = intensity * 10;
171-
line.style.filter = `drop-shadow(0 0 ${glowStrength}px rgba(255, 255, 255, 0.9))`;
172-
line.style.stroke = `rgba(255, 255, 255, ${intensity})`; // Glow overrides base opacity
173-
line.setAttribute('data-intensity', intensity.toString());
91+
// 高亮边框函数
92+
highlight(row, col) {
93+
const radius = 1.5;
94+
this.cells.forEach((cell) => {
95+
const r = parseInt(cell.dataset.row);
96+
const c = parseInt(cell.dataset.col);
97+
const dist = Math.hypot(r - row, c - col);
98+
99+
if (dist <= radius) {
100+
const intensity = 1 - dist / radius;
101+
const glow = Math.floor(200 + 55 * intensity);
102+
const color = `rgb(${glow}, ${glow}, ${glow})`;
103+
104+
if (window.gsap) {
105+
gsap.to(cell, {
106+
borderColor: color,
107+
boxShadow: `0 0 ${10 * intensity}px ${color}`,
108+
duration: 0.2
109+
});
110+
}
174111
} else {
175-
const currentIntensity = parseFloat(line.getAttribute('data-intensity') || "0");
176-
const newIntensity = Math.max(0, currentIntensity - 0.05); // Slower fade out
177-
line.setAttribute('data-intensity', newIntensity.toString());
178-
179-
if (newIntensity > 0) {
180-
const glowStrength = newIntensity * 10;
181-
line.style.filter = `drop-shadow(0 0 ${glowStrength}px rgba(255, 255, 255, 0.9))`;
182-
line.style.stroke = `rgba(255, 255, 255, ${Math.max(baseOpacity, newIntensity)})`;
112+
if (window.gsap) {
113+
gsap.to(cell, {
114+
borderColor: "rgba(255, 255, 255, 0.1)",
115+
boxShadow: "none",
116+
duration: 0.5
117+
});
183118
} else {
184-
line.style.filter = 'none';
185-
line.style.stroke = `rgba(255, 255, 255, ${baseOpacity})`;
186-
line.removeAttribute('data-intensity'); // Clean up attribute
119+
cell.style.borderColor = "rgba(255, 255, 255, 0.1)";
120+
cell.style.boxShadow = "none";
187121
}
188122
}
189123
});
190124
}
191125

192126
resetGrid() {
193-
this.lines.forEach(line => {
194-
const baseOpacity = parseFloat(line.getAttribute('data-base-opacity') || "0.15");
195-
line.style.filter = 'none';
196-
line.style.stroke = `rgba(255, 255, 255, ${baseOpacity})`;
197-
line.removeAttribute('data-intensity');
127+
this.cells.forEach((cell) => {
128+
if (window.gsap) {
129+
gsap.to(cell, {
130+
borderColor: "rgba(255, 255, 255, 0.1)",
131+
boxShadow: "none",
132+
duration: 0.5
133+
});
134+
} else {
135+
cell.style.borderColor = "rgba(255, 255, 255, 0.1)";
136+
cell.style.boxShadow = "none";
137+
}
198138
});
199139
}
200140
}
@@ -505,9 +445,9 @@ document.addEventListener('DOMContentLoaded', () => {
505445
});
506446
}
507447

508-
const svgElement = document.querySelector('.grid-overlay');
509-
if (svgElement) {
510-
new InteractiveGrid(svgElement);
448+
const gridElement = document.getElementById('grid');
449+
if (gridElement) {
450+
new InteractiveGrid(gridElement);
511451
}
512452

513453
// 第四页面的行星星星效果

styles/index/index.css

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ body {
6868
background: rgba(70, 48, 191, 0.4);
6969
filter: blur(64rem);
7070
animation: vibrate-1 7s ease-out infinite alternate forwards;
71-
z-index: 1;
71+
z-index: 5;
7272
}
7373

7474

@@ -82,17 +82,28 @@ body {
8282
filter: blur(64rem);
8383
opacity: 0.6;
8484
animation: vibrate-1 8s ease-out infinite alternate forwards;
85-
z-index: 1;
85+
z-index: 5;
8686
}
8787

8888
.grid-overlay {
89-
width: 75vw;
90-
height: 75vh;
89+
display: grid;
90+
width: 90vw;
91+
height: 90vh;
9192
position: absolute;
9293
top: 50%;
9394
left: 50%;
9495
transform: translate(-50%, -50%);
9596
pointer-events: all;
97+
grid-template-columns: repeat(12, 1fr);
98+
grid-template-rows: repeat(7, 1fr);
99+
z-index: 10;
100+
}
101+
102+
.grid-cell {
103+
background: transparent;
104+
border: 0.5px solid rgba(0, 0, 0, 0.1);
105+
box-sizing: border-box;
106+
transition: border-color 0.2s ease, box-shadow 0.2s ease;
96107
}
97108

98109
.page:nth-child(2) {

0 commit comments

Comments
 (0)