GSAP悬停动画异常:仅渲染时元素在视口才生效的问题求助
问题修复方案
问题现象
- 从页面顶部加载后滚动至目标区域,鼠标悬停动画无响应
- 页面加载时已处于目标区域,动画可正常触发
问题原因
你的HoverButton类仅在初始化和窗口 resize时调用calculatePosition()计算元素位置,但页面滚动时,元素的视口位置会发生变化,getBoundingClientRect()返回的坐标已失效,导致鼠标位置与元素中心的距离计算错误,无法触发hover逻辑。
修复代码
在attachEventsListener方法中添加scroll事件监听,每次滚动时重新计算元素位置:
(function() { class HoverButton { constructor(el) { this.el = el; this.hover = false; this.attachEventsListener(); this.calculatePosition(); } attachEventsListener() { window.addEventListener('mousemove', e => this.onMouseMove(e)); window.addEventListener('resize', e => this.calculatePosition(e)); // 添加scroll事件监听,滚动时重新计算元素位置 window.addEventListener('scroll', e => this.calculatePosition(e)); } calculatePosition() { gsap.set(this.el, { x: 0, y: 0, scale: 1 }); const box = this.el.getBoundingClientRect(); this.x = box.left + (box.width * 0.5); this.y = box.top + (box.height * 0.5); this.width = box.width; this.height = box.height; } onMouseMove(e) { let hover = false; let hoverArea = (this.hover ? 0.7 : 0.5); let x = e.clientX - this.x; let y = e.clientY - this.y; let distance = Math.sqrt(x * x + y * y); if (distance < (this.width * hoverArea)) { hover = true; if (!this.hover) { this.hover = true; } this.onHover(e.clientX, e.clientY); } if (!hover && this.hover) { this.onLeave(); this.hover = false; } } onHover(x, y) { gsap.to(this.el, { x: (x - this.x) * 0.4, y: (y - this.y) * 0.4, scale: 1.15, ease: 'power2.out', duration: 0.4 }); this.el.style.zIndex = 10; } onLeave() { gsap.to(this.el, { x: 0, y: 0, scale: 1, ease: 'elastic.out(1.2, 0.4)', duration: 0.7 }); this.el.style.zIndex = 10; } } const btn1 = document.querySelector('.under-splash__item--left>div:first-child'); new HoverButton(btn1); const btn2 = document.querySelector('.under-splash__item--right>div:first-child'); new HoverButton(btn2); const btn3 = document.querySelector('.products__item--air-purification>img'); new HoverButton(btn3); const btn4 = document.querySelector('.products__item--hvac-services>img'); new HoverButton(btn4); })();
额外优化建议
频繁的scroll事件会触发大量计算,可通过防抖函数优化性能,避免页面卡顿:
// 添加防抖工具函数 function debounce(func, delay = 100) { let timeoutId; return function(...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } // 在attachEventsListener中修改scroll监听 window.addEventListener('scroll', debounce(e => this.calculatePosition(e)));
内容的提问来源于stack exchange,提问作者dc89
相关产品推荐
相关产品推荐

