Mouseenter事件触发两次,div加载与hover动画不符合预期的问题排查
解决Div动画意外触发的问题
我来帮你搞定这个麻烦!咱们先拆解一下为啥会出现这些意外情况,再一步步修复:
问题根源分析
- 鼠标离开时动画重播:当你从hover状态切回默认状态时,浏览器会重新应用div的基础
animation(shake1),而CSS动画默认在属性变化时会从头播放,所以离开时会额外跑一次shake1。 - mouseenter触发两次:动画会改变元素的transform位置,可能导致鼠标短暂“离开”元素又重新进入,从而触发两次mouseenter事件。
修复方案:用类切换+动画事件控制
我们可以放弃hover伪类,改用JS添加/移除类来触发动画,同时限制初始动画只播放一次,彻底解决意外触发的问题。
完整代码示例
HTML
<div style="width:100px; height: 100px;"></div>
CSS
div { background: red; /* 初始动画只播放一次 */ animation-name: shake1; animation-duration: .5s; animation-iteration-count: 1; } @keyframes shake1 { 0% { transform: translate(1px, 1px) rotate(0deg); } 10% { transform: translate(-1px, -2px) rotate(-1deg); } 20% { transform: translate(-3px, 0px) rotate(1deg); } 30% { transform: translate(3px, 2px) rotate(0deg); } 40% { transform: translate(1px, -1px) rotate(1deg); } 50% { transform: translate(-1px, 2px) rotate(-1deg); } 60% { transform: translate(-3px, 1px) rotate(0deg); } 70% { transform: translate(3px, 1px) rotate(-1deg); } 80% { transform: translate(-1px, -1px) rotate(1deg); } 90% { transform: translate(1px, 2px) rotate(0deg); } 100% { transform: translate(1px, -2px) rotate(-1deg); } } /* 用类代替hover伪类触发shake2 */ .shake2 { animation-name: shake2; animation-duration: .5s; animation-iteration-count: 1; /* 动画期间阻止鼠标事件,避免位移导致的重复触发 */ pointer-events: none; } @keyframes shake2 { 0% { transform: translate(1px, 1px) rotate(0deg); } 10% { transform: translate(-1px, -2px) rotate(-1deg); } 20% { transform: translate(-3px, 0px) rotate(1deg); } 30% { transform: translate(3px, 2px) rotate(0deg); } 40% { transform: translate(1px, -1px) rotate(1deg); } 50% { transform: translate(-1px, 2px) rotate(-1deg); } 60% { transform: translate(-3px, 1px) rotate(0deg); } 70% { transform: translate(3px, 1px) rotate(-1deg); } 80% { transform: translate(-1px, -1px) rotate(1deg); } 90% { transform: translate(1px, 2px) rotate(0deg); } 100% { transform: translate(1px, -2px) rotate(-1deg); } }
JavaScript
const $image = document.querySelector("div"); $image.addEventListener("mouseenter", () => { // 先移除类再重新添加,确保每次进入都能触发动画 $image.classList.remove("shake2"); // 用requestAnimationFrame确保DOM更新后再添加类,避免无效操作 requestAnimationFrame(() => { $image.classList.add("shake2"); }); }); // 动画结束后清理类,恢复鼠标事件 $image.addEventListener("animationend", (e) => { if (e.animationName === "shake2") { $image.classList.remove("shake2"); $image.style.pointerEvents = "auto"; } });
修复后的效果
- 页面加载时,shake1动画只播放一次
- 鼠标进入div时,shake2动画播放一次,且不会重复触发mouseenter事件
- 鼠标离开div时,没有任何动画触发,完全符合预期
内容的提问来源于stack exchange,提问作者Sadiki
相关产品推荐
相关产品推荐

