讲师中心 微信公众号
AI工具推荐 视频效率加速

如何实现悬停时暂停动画并在鼠标离开后继续完成回弹动画

冬敏酱_5856

冬敏酱_5856

发布时间:2026-02-06 20:07:14

|

782人浏览过

|

来源于php中文网

原创

如何实现悬停时暂停动画并在鼠标离开后继续完成回弹动画

本文介绍一种基于 javascript 状态管理的 css 动画控制方案,解决「悬停触发正向旋转(-8° → 0°),鼠标离开后平滑回弹(0° → -8°)」的需求,避免元素因样式重置而突兀跳回初始状态。

要实现「鼠标悬停时启动正向旋转动画、离开时自动播放反向回弹动画,且两段动画均需完整执行、不中断、不跳变」,仅靠纯 CSS 的 :hover + transition 或简单 animation 类切换是不够的——因为 CSS 无法感知动画是否正在运行,也无法在动画中途响应 hover 状态变化。必须引入 JavaScript 进行动画生命周期监控与状态协同判断。

✅ 核心思路:双状态驱动

我们维护两个独立但关联的状态:

Json Repair Kit
Json Repair Kit

使用 Node.js 评估修复格式错误的 JSON,自动纠正尾随逗号、单引号、未加引号的键等常见问题,实现文件规范化。

下载
  • Hover 状态:通过 element.matches(':hover') 实时检测(比 mouseenter/mouseleave 更可靠,尤其应对快速进出场景);
  • 动画状态:用 Map 映射每个元素到其当前动画阶段(backward / forward / rotatingForward / rotatingBackward)。

只有当「当前处于 forward 状态且不再 hover」时,才触发回弹;同理,「当前处于 backward 状态且开始 hover」才触发正向旋转。这样确保动画不会被覆盖或打断。

✅ 关键技术点说明

  • animation-fill-mode: forwards:必须显式设置(代码中通过 style.animation = "... forwards" 实现),否则动画结束后元素会立即恢复原始 transform 值,造成“闪回”。
  • 监听 animationstart 和 animationend:精准捕获动画启停时刻,及时更新状态映射。
  • 直接操作 element.style.animation:比切换 class 更可控,旧动画会自动终止,新动画立即接管(无需手动 removeClass)。

✅ 完整可运行代码示例

<!DOCTYPE html>
<html>
<head>
<style>
.polaroid {
  width: 280px;
  height: 200px;
  padding: 10px 15px 100px 15px;
  border: 1px solid #bfbfbf;
  border-radius: 2%;
  background-color: white;
  box-shadow: 10px 10px 5px #aaaaaa;
  transform: rotate(-8deg); /* 初始角度 */
  cursor: pointer;
}

@keyframes rotate-forward {
  from { transform: rotate(-8deg); }
  to   { transform: rotate(0deg); }
}

@keyframes rotate-backward {
  from { transform: rotate(0deg); }
  to   { transform: rotate(-8deg); }
}
</style>
</head>
<body>

<div class="polaroid">
  <p class="caption">Just a basic explanation of the picture.</p>
</div>
<div class="polaroid">
  <p class="caption">Second polaroid with same behavior.</p>
</div>

<script>
const rotateForwardAnimationName = 'rotate-forward';
const rotateBackwardAnimationName = 'rotate-backward';

const states = {
  forward: 'forward',
  backward: 'backward',
  rotatingForward: 'rotatingForward',
  rotatingBackward: 'rotatingBackward',
};

const elements = document.querySelectorAll('.polaroid');
const stateMap = new Map();

// 初始化所有元素为 backward 状态
elements.forEach(el => stateMap.set(el, states.backward));

elements.forEach(element => {
  // 监听动画事件
  element.addEventListener('animationstart', (e) => {
    if (e.animationName === rotateForwardAnimationName) {
      stateMap.set(element, states.rotatingForward);
    } else if (e.animationName === rotateBackwardAnimationName) {
      stateMap.set(element, states.rotatingBackward);
    }
    onStateUpdate(element);
  });

  element.addEventListener('animationend', (e) => {
    if (e.animationName === rotateForwardAnimationName) {
      stateMap.set(element, states.forward);
    } else if (e.animationName === rotateBackwardAnimationName) {
      stateMap.set(element, states.backward);
    }
    onStateUpdate(element);
  });

  // 监听 hover 变化(mouseenter/mouseleave 非必需,但增强响应性)
  element.addEventListener('mouseenter', () => onStateUpdate(element));
  element.addEventListener('mouseleave', () => onStateUpdate(element));
});

function onStateUpdate(element) {
  const isHovered = element.matches(':hover');
  const currentState = stateMap.get(element);

  if (currentState === states.forward && !isHovered) {
    rotateBackward(element);
  } else if (currentState === states.backward && isHovered) {
    rotateForward(element);
  }
}

function rotateForward(element) {
  element.style.animation = `${rotateForwardAnimationName} 2s forwards`;
}

function rotateBackward(element) {
  element.style.animation = `${rotateBackwardAnimationName} 2s forwards`;
}
</script>

</body>
</html>

⚠️ 注意事项

  • 不要使用 transition 混合 animation:二者机制不同,混合易导致行为不可控;
  • 避免在 :hover 中直接写 transform:这会覆盖 animation 的 forwards 效果,造成跳变;
  • 若需支持旧版 IE,请补充 -ms-transform 等前缀(现代项目通常可忽略);
  • 多个元素共用同一套逻辑?✅ querySelectorAll + forEach 已天然支持。

✅ 总结

该方案将「动画控制权」从 CSS 移交至 JS,通过精细化的状态协同,实现了真正符合直觉的悬停交互体验:动画不中断、不跳帧、不重置,进退皆从容。适用于 Polaroid 相框、卡片翻转、图标悬停动效等需要精确时序控制的 UI 场景。

热门AI工具

更多
超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
php中foreach用法
php中foreach用法

本专题整合了php中foreach用法的相关介绍,阅读专题下面的文章了解更多详细教程。

778

2025.12.04

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

4056

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

306

2025.12.06

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

610

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

343

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

533

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

303

2025.11.27

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

4476

2023.06.20

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

40

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Sass 教程
Sass 教程

共14课时 | 1.5万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 6万人学习

CSS教程
CSS教程

共754课时 | 98.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn