Skip to content

Commit d4cbfe1

Browse files
committed
feat(GlobalQuickReport): 优化页面交互效果
- 新增新闻弹窗动画效果,提升用户体验 - 优化视频弹窗关闭动画,使过渡更流畅 - 为新闻项和视频按钮添加点击反馈动画,增强交互性 - 预创建新闻弹窗元素,避免重复创建,提高性能 - 使用 GSAP ScrollTrigger 优化页面滚动效果 - 调整部分样式,如移除不必要的动画和过渡效果,提高页面响应速度
1 parent 73eec1a commit d4cbfe1

3 files changed

Lines changed: 227 additions & 62 deletions

File tree

pages/GlobalQuickReport.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
</div>
5151
</div>
5252
<script src="../build/gsap.js"></script>
53+
<script src="../build/scrolltrigger.js"></script>
5354
<script src="../build/three_r145.js"></script>
5455
<script src="../build/three_objloader.js"></script>
5556
<script src="../scripts/common/HeaderController.js"></script>

scripts/GlobalQuickReport/index.js

Lines changed: 209 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -94,68 +94,171 @@ const gkhz = [
9494
}
9595
]
9696

97+
// 预创建新闻弹窗元素,避免重复创建
98+
let newsModalOverlay = null;
99+
100+
function createNewsModal() {
101+
if (newsModalOverlay) return newsModalOverlay;
102+
103+
newsModalOverlay = document.createElement('div');
104+
newsModalOverlay.className = 'news-modal-overlay';
105+
newsModalOverlay.innerHTML = `
106+
<div class="new-content-box">
107+
<div class="close-btn"></div>
108+
<div class="children">
109+
<div class="new-box-title"></div>
110+
<div class="line"></div>
111+
<p class="new-content"></p>
112+
</div>
113+
</div>
114+
`;
115+
116+
document.body.appendChild(newsModalOverlay);
117+
118+
// 为关闭按钮添加事件监听器
119+
const closeBtn = newsModalOverlay.querySelector('.close-btn');
120+
closeBtn.addEventListener('click', (e) => {
121+
e.stopPropagation();
122+
hideNewsModal();
123+
});
124+
125+
// 点击背景关闭弹窗
126+
newsModalOverlay.addEventListener('click', (e) => {
127+
if (e.target === newsModalOverlay) {
128+
hideNewsModal();
129+
}
130+
});
131+
132+
// 初始隐藏
133+
newsModalOverlay.style.display = 'none';
134+
135+
return newsModalOverlay;
136+
}
137+
138+
function showNewsModal(newsItem) {
139+
const modalOverlay = createNewsModal();
140+
141+
// 更新内容
142+
modalOverlay.querySelector('.new-box-title').textContent = newsItem.title;
143+
144+
// 对长内容进行处理,提高渲染性能
145+
const contentElement = modalOverlay.querySelector('.new-content');
146+
contentElement.textContent = newsItem.content;
147+
148+
// 显示弹窗
149+
modalOverlay.style.display = 'flex';
150+
151+
// 使用GSAP动画显示弹窗
152+
gsap.set(modalOverlay, { opacity: 0 });
153+
gsap.set(modalOverlay.querySelector('.children'), { y: 50, opacity: 0 });
154+
155+
const tl = gsap.timeline();
156+
tl.to(modalOverlay, {
157+
opacity: 1,
158+
duration: 0.3,
159+
ease: "power2.out"
160+
})
161+
.to(modalOverlay.querySelector('.children'), {
162+
y: 0,
163+
opacity: 1,
164+
duration: 0.4,
165+
ease: "back.out(1.7)"
166+
}, "-=0.1");
167+
}
168+
169+
function hideNewsModal() {
170+
const modalOverlay = newsModalOverlay;
171+
if (!modalOverlay || modalOverlay.style.display === 'none') return;
172+
173+
// 使用GSAP动画关闭弹窗
174+
const tl = gsap.timeline({
175+
onComplete: () => {
176+
modalOverlay.style.display = 'none';
177+
}
178+
});
179+
tl.to(modalOverlay.querySelector('.children'), {
180+
y: 50,
181+
opacity: 0,
182+
duration: 0.3,
183+
ease: "power2.in"
184+
})
185+
.to(modalOverlay, {
186+
opacity: 0,
187+
duration: 0.2,
188+
ease: "power2.in"
189+
}, "-=0.1");
190+
}
191+
192+
// 防抖函数,防止频繁点击
193+
function debounce(func, wait) {
194+
let timeout;
195+
return function executedFunction(...args) {
196+
const later = () => {
197+
clearTimeout(timeout);
198+
func(...args);
199+
};
200+
clearTimeout(timeout);
201+
timeout = setTimeout(later, wait);
202+
};
203+
}
204+
97205
function createNewsItem(news = []) {
98206
const newsContainer = document.querySelector('.news');
207+
if (!newsContainer) return;
208+
99209
newsContainer.innerHTML = news.map((item, index) =>
100210
`<div class="new-item" data-index="${index}">
101211
<div class="title">${item.title}</div>
102212
<div class="date">${item.date}</div>
103213
</div>`
104214
).join('');
105215

106-
newsContainer.addEventListener('click', (event) => {
216+
// 使用事件委托处理点击事件,避免为每个新闻项单独绑定事件
217+
// 添加防抖处理,防止频繁点击
218+
const debouncedClickHandler = debounce((event) => {
107219
const target = event.target.closest('.new-item');
108220
if (target) {
221+
// 添加点击反馈动画
222+
gsap.to(target, {
223+
scale: 0.98,
224+
duration: 0.1,
225+
yoyo: true,
226+
repeat: 1,
227+
ease: "power2.out"
228+
});
229+
109230
const index = target.getAttribute('data-index');
110231
const newsItem = news[index];
111232

112-
// 移除已存在的弹窗
113-
const existingModal = document.querySelector('.news-modal-overlay');
114-
if (existingModal) {
115-
existingModal.remove();
116-
}
117-
118-
// 创建新的弹窗并添加到body
119-
const modalOverlay = document.createElement('div');
120-
modalOverlay.className = 'news-modal-overlay';
121-
modalOverlay.innerHTML = `
122-
<div class="new-content-box">
123-
<div class="close-btn"></div>
124-
<div class="children">
125-
<div class="new-box-title">${newsItem.title}</div>
126-
<div class="line"></div>
127-
<p class="new-content">${newsItem.content}</p>
128-
</div>
129-
</div>
130-
`;
131-
132-
document.body.appendChild(modalOverlay);
133-
134-
// 显示弹窗
135-
setTimeout(() => {
136-
modalOverlay.style.opacity = '1';
137-
}, 10);
138-
139-
const closeBtn = modalOverlay.querySelector('.close-btn');
140-
closeBtn.addEventListener('click', (e) => {
141-
e.stopPropagation();
142-
modalOverlay.remove();
143-
});
144-
145-
// 点击背景关闭弹窗
146-
modalOverlay.addEventListener('click', (e) => {
147-
if (e.target === modalOverlay) {
148-
modalOverlay.remove();
149-
}
150-
});
233+
showNewsModal(newsItem);
151234
}
152-
});
235+
}, 300); // 300ms防抖延迟
236+
237+
newsContainer.addEventListener('click', debouncedClickHandler);
153238
}
154239

155240
function createPopupVideoOverlay(videoSrc) {
156241
// 如果已有弹窗,先清除
157242
const existing = document.querySelector('.video-popup-overlay');
158-
if (existing) existing.remove();
243+
if (existing) {
244+
// 使用GSAP动画关闭现有弹窗
245+
const tl = gsap.timeline({
246+
onComplete: () => {
247+
existing.remove();
248+
}
249+
});
250+
tl.to(existing.querySelector('.video-popup'), {
251+
scale: 0.8,
252+
opacity: 0,
253+
duration: 0.3,
254+
ease: "power2.in"
255+
})
256+
.to(existing, {
257+
opacity: 0,
258+
duration: 0.2,
259+
ease: "power2.in"
260+
}, "-=0.1");
261+
}
159262

160263
const overlay = document.createElement('div');
161264
overlay.className = 'video-popup-overlay';
@@ -168,14 +271,48 @@ function createPopupVideoOverlay(videoSrc) {
168271

169272
document.body.appendChild(overlay);
170273

274+
// 使用GSAP动画显示弹窗
275+
gsap.set(overlay, { opacity: 0 });
276+
gsap.set(overlay.querySelector('.video-popup'), { scale: 0.8, opacity: 0 });
277+
278+
const tl = gsap.timeline();
279+
tl.to(overlay, {
280+
opacity: 1,
281+
duration: 0.3,
282+
ease: "power2.out"
283+
})
284+
.to(overlay.querySelector('.video-popup'), {
285+
scale: 1,
286+
opacity: 1,
287+
duration: 0.4,
288+
ease: "back.out(1.7)"
289+
}, "-=0.1");
290+
171291
overlay.querySelector('.close-video-btn').addEventListener('click', () => {
172-
overlay.remove();
292+
// 使用GSAP动画关闭弹窗
293+
const tl = gsap.timeline({
294+
onComplete: () => {
295+
overlay.remove();
296+
}
297+
});
298+
tl.to(overlay.querySelector('.video-popup'), {
299+
scale: 0.8,
300+
opacity: 0,
301+
duration: 0.3,
302+
ease: "power2.in"
303+
})
304+
.to(overlay, {
305+
opacity: 0,
306+
duration: 0.2,
307+
ease: "power2.in"
308+
}, "-=0.1");
173309
});
174310
}
175311

176-
177312
function initHTKJYYYMSFW() {
178313
const container = document.querySelector('.htkj-yyymsfw');
314+
if (!container) return;
315+
179316
container.innerHTML = htkjyymfw.map((item, index) =>
180317
`<div class="item">
181318
<img src="${item.img}" data-index="${index}" alt="HTKJYYYMSFW Image">
@@ -185,6 +322,15 @@ function initHTKJYYYMSFW() {
185322
container.addEventListener('click', (event) => {
186323
const img = event.target.closest('img');
187324
if (img) {
325+
// 添加点击反馈动画
326+
gsap.to(img, {
327+
scale: 0.95,
328+
duration: 0.1,
329+
yoyo: true,
330+
repeat: 1,
331+
ease: "power2.out"
332+
});
333+
188334
const index = img.dataset.index;
189335
const videoSrc = htkjyymfw[index].vodeo;
190336
createPopupVideoOverlay(videoSrc);
@@ -194,6 +340,8 @@ function initHTKJYYYMSFW() {
194340

195341
function initGJHZ() {
196342
const container = document.querySelector('.gjhz');
343+
if (!container) return;
344+
197345
container.innerHTML = gkhz.map((item, index) =>
198346
`<div class="item">
199347
<img src="${item.img}" data-index="${index}" alt="GKHZ Image">
@@ -203,6 +351,15 @@ function initGJHZ() {
203351
container.addEventListener('click', (event) => {
204352
const img = event.target.closest('img');
205353
if (img) {
354+
// 添加点击反馈动画
355+
gsap.to(img, {
356+
scale: 0.95,
357+
duration: 0.1,
358+
yoyo: true,
359+
repeat: 1,
360+
ease: "power2.out"
361+
});
362+
206363
const index = img.dataset.index;
207364
const videoSrc = gkhz[index].vodeo;
208365
createPopupVideoOverlay(videoSrc);
@@ -211,14 +368,17 @@ function initGJHZ() {
211368
}
212369

213370
document.addEventListener("DOMContentLoaded", () => {
371+
// 初始化GSAP ScrollTrigger
372+
gsap.registerPlugin(ScrollTrigger);
373+
214374
const header = document.querySelector('.header');
215375
const scrollContainer = document.querySelector('.container');
216376
const starBg = document.querySelector('.star-bg');
377+
if (!header || !scrollContainer || !starBg) return;
217378

218379
// 初始化头部控制器
219380
new HeaderController(header, { scrollContainer });
220381

221-
222382
// 初始化鼠标控制器
223383
new Mouse({
224384
defaultCursor: '../assets/images/common/MouseDefault.svg',
@@ -232,6 +392,9 @@ document.addEventListener("DOMContentLoaded", () => {
232392

233393
new MeteorEffect(starBg)
234394

395+
// 预创建新闻弹窗
396+
createNewsModal();
397+
235398
// 创建新闻项
236399
createNewsItem(news);
237400

@@ -240,4 +403,4 @@ document.addEventListener("DOMContentLoaded", () => {
240403

241404
// 初始化GKHZ
242405
initGJHZ();
243-
});
406+
});

0 commit comments

Comments
 (0)