使用GSAP实现悬停下拉列表动画时出现抖动问题的咨询
解决GSAP下拉列表悬停抖动问题
抖动的核心原因是动画过程中容器位置(y值)变化导致鼠标意外触发mouseleave事件,加上固定height与maxHeight的冲突,引发动画反复触发。以下是两种基于GSAP的修复方案:
方案一:固定容器位置,仅动画列表内容
这种方式避免移动整个下拉容器,只让隐藏的列表部分滑入,彻底消除鼠标位置偏移的问题:
修改后的代码
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script> <div class="languages-dropdown"> <p class="title">Języki programowania</p> <div class="language-list"> <br> <a href="subpages/sub-page0.html" class="language">Javascript</a> <a href="subpages/sub-page1.html" class="language">B</a> <a href="subpages/sub-page2.html" class="language">C</a> <a href="subpages/sub-page3.html" class="language">C++</a> <a href="subpages/sub-page4.html" class="language">C#</a> <a href="subpages/sub-page5.html" class="language">Rust</a> <a href="subpages/sub-page6.html" class="language">Java</a> <a href="subpages/sub-page7.html" class="language">Python</a> <a href="subpages/sub-page8.html" class="language">Golang</a> <a href="subpages/sub-page9.html" class="language">PHP</a> </div> </div>
CSS
.languages-dropdown { position: absolute; padding: 17px; border: none; border-radius: 10px; background-color: rgb(53, 53, 53); width: 230px; overflow: hidden; max-height: 59px; /* 初始仅显示标题的高度 */ } .title { text-align: center; font-size: 20px; margin: 0; /* 清除默认margin,避免高度计算偏差 */ } .language-list { margin-left: 60px; } .language { display: block; text-decoration: none; padding: 5px; font-size: 17px; }
JS
let languagesDropdown = document.querySelector(".languages-dropdown") let languageList = document.querySelector(".language-list") // 初始化列表位置,向上隐藏 gsap.set(languageList, { y: -languageList.offsetHeight }) languagesDropdown.addEventListener("mouseenter", () => { // 展开容器高度 gsap.to(languagesDropdown, { ease: "power1.inOut", duration: 0.2, maxHeight: 375, }); // 滑入列表 gsap.to(languageList, { ease: "power1.inOut", duration: 0.2, y: 0, }); }); languagesDropdown.addEventListener("mouseleave", () => { // 收缩容器高度 gsap.to(languagesDropdown, { ease: "power1.inOut", duration: 0.2, maxHeight: 59, }); // 滑出列表 gsap.to(languageList, { ease: "power1.inOut", duration: 0.2, y: -languageList.offsetHeight, }); });
方案二:保留容器移动,禁用动画过程中的事件冲突
如果必须移动容器位置,可通过临时禁用鼠标事件,避免动画过程中误触发mouseleave:
修改后的JS代码
let languagesDropdown = document.querySelector(".languages-dropdown") gsap.set(languagesDropdown, { y: -250 }) languagesDropdown.addEventListener("mouseenter", () => { gsap.to(languagesDropdown, { ease: "power1.inOut", duration: 0.2, y: -92, maxHeight: "375px", pointerEvents: "none", // 动画过程中禁用鼠标事件 onComplete: () => { languagesDropdown.style.pointerEvents = "auto" // 动画结束恢复 } }); }); languagesDropdown.addEventListener("mouseleave", () => { gsap.to(languagesDropdown, { ease: "power1.inOut", duration: 0.2, y: -250, maxHeight: 59, pointerEvents: "none", onComplete: () => { languagesDropdown.style.pointerEvents = "auto" } }); });
关键优化说明
- 方案一从根源解决问题:固定容器位置,仅动画内部列表,避免鼠标因容器移动意外移出触发事件。
- 方案二通过
pointerEvents临时禁用事件,防止动画过程中反复触发enter/leave。 - 移除CSS中固定的
height值,让maxHeight基于实际内容计算,避免动画结束后高度异常。
内容的提问来源于stack exchange,提问作者MiszS
相关产品推荐
相关产品推荐

