0

0

如何实现悬停暂停动画并在鼠标离开后平滑恢复原状态

花韻仙語

花韻仙語

发布时间:2026-02-06 22:42:59

|

636人浏览过

|

来源于php中文网

原创

如何实现悬停暂停动画并在鼠标离开后平滑恢复原状态

本文详解如何通过 javascript 精确控制 css 动画状态,实现元素在 hover 时从 -8° 旋转至 0°、鼠标离开后平滑返回 -8° 的无缝过渡效果,避免“跳变”或状态丢失。

要实现「悬停触发正向旋转 → 停留在目标角度 → 鼠标离开后平滑反向旋转回起始角度」这一行为,仅靠纯 CSS :hover + transition 或简单类名切换是不够的:transition 在鼠标移出瞬间会中断当前状态并立即插值回初始值,导致“突兀回弹”;而基于 animation 的类名切换又缺乏对动画生命周期的细粒度感知,容易因重复触发造成状态错乱。

✅ 正确解法是将动画控制权交还 JavaScript,通过监听 animationstart/animationend 与 mouseenter/mouseleave 事件,构建双状态机(hover 状态 + 动画执行状态),确保:

  • 动画一旦开始,必须完整播放完毕(animation-fill-mode: forwards 是关键);
  • 只有在动画真正结束且状态匹配时,才触发下一段动画;
  • 多个元素可独立运行,互不干扰。

以下是完整、可直接复用的实现方案:

语鹦学舌
语鹦学舌

三步生成专属AI数字人分身,文字秒变视频

下载

✅ 核心 JavaScript(推荐 ES6+ 写法)

const ROTATE_FORWARD = 'rotate-forward';
const ROTATE_BACKWARD = 'rotate-backward';

// 四种互斥动画状态
const STATES = {
  backward: 'backward',      // 已完成反向动画,静止于 -8deg
  forward: 'forward',        // 已完成正向动画,静止于 0deg
  rotatingForward: 'rotatingForward',
  rotatingBackward: 'rotatingBackward'
};

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

elements.forEach(el => {
  stateMap.set(el, STATES.backward); // 初始状态为 backward

  // 监听动画生命周期
  el.addEventListener('animationstart', (e) => {
    if (e.animationName === ROTATE_FORWARD)
      stateMap.set(el, STATES.rotatingForward);
    else if (e.animationName === ROTATE_BACKWARD)
      stateMap.set(el, STATES.rotatingBackward);
    updateState(el);
  });

  el.addEventListener('animationend', (e) => {
    if (e.animationName === ROTATE_FORWARD)
      stateMap.set(el, STATES.forward);
    else if (e.animationName === ROTATE_BACKWARD)
      stateMap.set(el, STATES.backward);
    updateState(el);
  });

  // 监听交互
  el.addEventListener('mouseenter', () => updateState(el));
  el.addEventListener('mouseleave', () => updateState(el));
});

function updateState(el) {
  const isHovered = el.matches(':hover');
  const state = stateMap.get(el);

  // 状态决策表(核心逻辑)
  if (state === STATES.forward && !isHovered) {
    rotateBackward(el);
  } else if (state === STATES.backward && isHovered) {
    rotateForward(el);
  }
}

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

function rotateBackward(el) {
  el.style.animation = `${ROTATE_BACKWARD} 2s forwards`;
}

✅ 对应 CSS(精简无冗余)

.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); /* 初始角度 */
  /* 移除所有 transition,交由 animation 控制 */
}

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

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

✅ HTML 结构(简洁语义化)

Just a basic explanation of the picture.

Second polaroid with same behavior.

⚠️ 关键注意事项

  • forwards 不可省略:animation: name 2s forwards 中的 forwards 确保动画结束后样式保持在 to 关键帧状态(如 rotate(0deg)),否则动画一结束就会“闪回”初始值。
  • 避免 transition 干扰:CSS 中务必移除所有 transform 相关的 transition,否则它会与 animation 冲突,导致不可预测的混合动画。
  • 状态映射需唯一:使用 Map 而非全局变量或 data-* 属性,保证每个 .polaroid 元素拥有独立状态,支持无限扩展。
  • 无需 !important 或内联 style 清理:本方案通过覆盖 style.animation 实现原子级控制,旧动画自动终止,无需手动 remove() 类名或清空 style。

✅ 效果验证要点

场景 预期行为
首次 hover 平滑旋转至 0deg,停住
hover 中快速进出多次 不触发新动画(因状态为 rotatingForward,不满足触发条件)
hover 后 mouseleave 待正向动画结束,立即启动反向动画,平滑转回 -8deg
移动中突然 hover 若当前在 rotatingBackward,则停止并等待 hover 触发正向动画(符合状态机设计)

该方案兼顾健壮性、可维护性与性能——无定时器、无强制重排、无内存泄漏风险,是现代 Web 动画控制的推荐实践。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
es6新特性
es6新特性

es6新特性有:1、块级作用域变量;2、箭头函数;3、模板字符串;4、解构赋值;5、默认参数;6、 扩展运算符;7、 类和继承;8、Promise。本专题为大家提供es6新特性的相关的文章、下载、课程内容,供大家免费下载体验。

106

2023.07.17

es6新特性有哪些
es6新特性有哪些

es6的新特性有:1、块级作用域;2、箭头函数;3、解构赋值;4、默认参数;5、扩展运算符;6、模板字符串;7、类和模块;8、迭代器和生成器;9、Promise对象;10、模块化导入和导出等等。本专题为大家提供es6新特性的相关的文章、下载、课程内容,供大家免费下载体验。

196

2023.08.04

JavaScript ES6新特性
JavaScript ES6新特性

ES6是JavaScript的根本性升级,引入let/const实现块级作用域、箭头函数解决this绑定问题、解构赋值与模板字符串简化数据处理、对象简写与模块化提升代码可读性与组织性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

224

2025.12.24

全局变量怎么定义
全局变量怎么定义

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

82

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

98

2025.09.18

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

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

75

2025.09.05

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

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

36

2025.11.16

golang map原理
golang map原理

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

64

2025.11.17

Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

2

2026.02.06

热门下载

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

精品课程

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

共14课时 | 0.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.2万人学习

CSS教程
CSS教程

共754课时 | 28.2万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号