Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
JavaScript控制CSS动画重复触发失效问题及解决方案_创想鸟

JavaScript控制CSS动画重复触发失效问题及解决方案

JavaScript控制CSS动画重复触发失效问题及解决方案

当通过javascript移除并立即重新添加css动画类时,浏览器可能因优化机制导致动画无法重复播放。本教程将深入分析此问题,并提供一个使用settimeout延迟动画类添加的有效解决方案,确保css动画每次都能成功触发,实现预期的视觉效果。

1. 问题背景与现象

在前端开发中,我们经常需要通过JavaScript动态地添加或移除CSS类来控制元素的样式或触发动画。然而,一个常见的问题是,当一个包含CSS动画的类被移除后又立即重新添加时,动画可能只在第一次点击时生效,后续点击则无法再次触发。

例如,考虑以下场景:页面上有两个按钮,分别控制两个方块的动画效果。点击按钮后,对应的方块会闪烁黄色并最终变为蓝色。但实际操作中,第一次点击按钮动画正常播放,再次点击时方块没有任何变化。

初始代码结构示例:

HTML

立即学习“Java免费学习笔记(深入)”;



CSS

#bases {  position: absolute;  top: 0px;  left: 0px;  height: 20vw;  width: 20vw;  margin-top: 5vw;  margin-right: 5vw;}.base {  background: rgb(44, 44, 44);  border-style: solid;  border-width: thick;  box-shadow: -8px 8px 20px black;  width: 42%;  height: 42%;  position: absolute;}#b1 {  bottom: 0;  left: 0;}#b2 {  top: 0;  left: 0;}.animatedBaseHit {  animation: pulseBaseHit 0.8s 3; /* 动画持续0.8s,播放3次 */}@keyframes pulseBaseHit {  0% {    transform: scale(1.05);    background: yellow;  }  50% {    transform: scale(0.9);    background: rgb(44, 44, 44);    box-shadow: -2px 2px 20px black;  }  100% {    transform: scale(1.05);    background: yellow;  }}.occupiedBase {  background: blue;}

JavaScript

const BaseHTMLCollection = [document.getElementById("b1"), document.getElementById("b2")];function clearBase(b) {  BaseHTMLCollection[b].classList.remove("occupiedBase");  BaseHTMLCollection[b].classList.remove("animatedBaseHit");}function flashBaseColor(b, a) {  if (a == "H") {    BaseHTMLCollection[b].classList.add("animatedBaseHit"); // 添加动画类  }}function updateBaseColor(b, a) {  BaseHTMLCollection[b].classList.add("occupiedBase");  if (b == 1) {    BaseHTMLCollection[b - 1].classList.remove("occupiedBase");  }}function baseAction(base, action) {  clearBase(base); // 移除动画类  flashBaseColor(base, action); // 再次添加动画类  updateBaseColor(base, action);}

在上述JavaScript代码中,baseAction 函数首先调用 clearBase 移除了 animatedBaseHit 类,然后紧接着调用 flashBaseColor 重新添加了 animatedBaseHit 类。这种立即移除又立即添加的行为,是导致动画无法重复触发的根本原因。

2. 问题分析:浏览器渲染优化机制

CSS动画的触发机制依赖于浏览器对元素样式的感知。当一个元素被赋予了包含动画定义的类时,浏览器会开始执行动画。如果这个类被移除,动画就会停止。

问题在于,当JavaScript在同一个事件循环(event loop)中,即在同一个函数调用栈中,快速地移除一个动画类并立即重新添加它时,浏览器可能不会立即重新计算并渲染DOM的变化。为了性能优化,浏览器通常会将一系列DOM操作批处理后统一渲染。这意味着,classList.remove(“animatedBaseHit”) 和 classList.add(“animatedBaseHit”) 可能会被浏览器合并处理,导致它认为该类实际上并未被“真正”移除或重新添加,从而动画状态未被重置,也就无法再次触发。

简单来说,浏览器需要一个“喘息”的时间来注册动画类的移除,然后才能再次注册其添加,从而触发新的动画周期。

3. 解决方案:利用 setTimeout 延迟类添加

解决此问题的核心思路是,在移除动画类之后,给浏览器一个机会来处理这个移除操作,然后再重新添加动画类。setTimeout 是实现这一目标的一个简单而有效的方法。通过将 classList.add() 操作包裹在一个 setTimeout 回调函数中,即使延迟时间设置为0毫秒,也能将该操作推迟到当前事件循环的末尾,即下一个事件循环周期执行。这使得浏览器有足够的时间来处理前一个 classList.remove() 操作。

修改方案:

在 flashBaseColor 函数中,修改添加 animatedBaseHit 类的方式:

function flashBaseColor(b, a) {  if (a == "H") {    // 1. 确保在添加之前移除动画类,即使它可能已被 clearBase 移除    BaseHTMLCollection[b].classList.remove("animatedBaseHit");    // 2. 使用 setTimeout 延迟动画类的添加    setTimeout(() => {      BaseHTMLCollection[b].classList.add("animatedBaseHit");    }, 0); // 0ms 延迟将任务推入事件队列的下一个宏任务  }}

解释:

BaseHTMLCollection[b].classList.remove(“animatedBaseHit”);:这一行是关键,它确保在尝试重新添加动画类之前,该类已经被明确移除。即使 clearBase 已经执行过,再次移除也无害。setTimeout(() => { … }, 0);:这是解决方案的核心。它将 classList.add(“animatedBaseHit”) 操作放入一个异步任务中。当 baseAction 函数执行完毕,当前的同步任务栈清空后,事件循环会处理 setTimeout 中的回调函数,此时浏览器已经完成了对 animatedBaseHit 类移除的渲染处理,因此重新添加该类就能成功触发动画。

4. 完整代码示例(JavaScript 部分)

将上述修改应用到原始的JavaScript代码中:

const BaseHTMLCollection = [document.getElementById("b1"), document.getElementById("b2")];function clearBase(b) {  BaseHTMLCollection[b].classList.remove("occupiedBase");  BaseHTMLCollection[b].classList.remove("animatedBaseHit"); // 移除动画类}function flashBaseColor(b, a) {  if (a == "H") {    // 确保动画类被移除,以便后续重新添加能触发动画    BaseHTMLCollection[b].classList.remove("animatedBaseHit");    // 使用 setTimeout 延迟动画类的添加,强制浏览器重置动画状态    setTimeout(() => {      BaseHTMLCollection[b].classList.add("animatedBaseHit");    }, 0);  }}function updateBaseColor(b, a) {  BaseHTMLCollection[b].classList.add("occupiedBase");  if (b == 1) {    BaseHTMLCollection[b - 1].classList.remove("occupiedBase");  }}function baseAction(base, action) {  clearBase(base); // 移除旧状态和动画类  flashBaseColor(base, action); // 触发新的动画  updateBaseColor(base, action); // 更新其他颜色状态}

通过这个修改,每次点击按钮时,animatedBaseHit 类都会被先移除,然后在一个微小的延迟后重新添加,从而确保CSS动画能够被浏览器正确识别并重复触发。

5. 注意事项与最佳实践

setTimeout(…, 0) 的理解:0毫秒的延迟并不意味着立即执行。它意味着将回调函数放入事件队列的末尾,等待当前同步代码执行完毕后,在下一个事件循环周期中执行。这对于强制浏览器重绘或重置动画状态非常有效。强制重绘/回流(Reflow/Repaint):除了 setTimeout,另一种强制浏览器重置动画状态的方法是强制浏览器进行重绘或回流。例如,在移除类后立即访问元素的某个会触发回流的属性(如 element.offsetWidth),然后再添加类。但 setTimeout(…, 0) 通常更简洁且副作用小。动画事件监听:对于更复杂的动画控制,可以考虑使用 animationend 或 transitionend 事件监听器。当动画结束时,移除动画类,并在下次需要时再添加。性能考量:对于频繁触发的动画,过度使用 setTimeout 或强制重绘可能带来轻微的性能开销。但对于用户交互触发的动画,这种开销通常可以忽略不计。

6. 总结

当JavaScript动态控制CSS动画时,如果遇到动画类移除后无法重复触发的问题,其根本原因在于浏览器对DOM操作的优化。通过在移除动画类后,使用 setTimeout 延迟其重新添加,我们可以有效地强制浏览器重置动画状态,从而确保动画能够按预期重复播放。掌握这一技巧,能帮助开发者更灵活、更可靠地实现基于CSS的动态视觉效果。

以上就是JavaScript控制CSS动画重复触发失效问题及解决方案的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1583426.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
正确处理下拉列表数据与Chart.js图表联动问题
上一篇 2025年12月23日 00:01:02
动态HTML表格过滤教程:实现交互式数据搜索
下一篇 2025年12月23日 00:01:12

相关推荐

  • mysql添加索引命令 mysql创建普通唯一复合索引教程

    mysql添加索引命令 mysql创建普通唯一复合索引教程mysql添加索引命令 mysql创建普通唯一复合索引教程mysql添加索引命令 mysql创建普通唯一复合索引教程mysql添加索引命令 mysql创建普通唯一复合索引教程

    在mysql中给表加索引的核心目的是提升查询效率。解决方案是通过create index或alter table语句创建不同类型的索引:1. 普通索引用于加快非唯一列的查询;2. 唯一索引确保列值唯一性并提升性能;3. 复合索引支持多列组合查询,遵循最左前缀原则;4. 复合唯一索引结合复合和唯一特性…

    2026年9月23日 • 用户投稿
    000
  • VSCode快速配置React:JSX支持、中文文档、组件调试

    首先确保安装es7 react/redux/graphql/react-native snippets扩展并配置jsconfig.json文件以启用jsx语法高亮;通过安装中文语言包汉化界面,并结合浏览器书签、翻译工具及笔记软件高效查阅react中文文档;调试react组件时需安装debugger …

    2026年9月23日
    100
  • PaintToolSAI的AI功能如何裁剪图片?教你精准实现裁剪方法

    PaintToolSAI的AI功能如何裁剪图片?教你精准实现裁剪方法PaintToolSAI的AI功能如何裁剪图片?教你精准实现裁剪方法PaintToolSAI的AI功能如何裁剪图片?教你精准实现裁剪方法PaintToolSAI的AI功能如何裁剪图片?教你精准实现裁剪方法

    PaintToolSAI没有AI裁剪功能,其裁剪依赖手动操作。用户需使用选区工具框选区域,再通过“画布→裁剪”完成,过程基础但精确,适合专注绘画而非复杂图像处理的场景。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ PaintToolSAI…

    2026年9月23日 • 用户投稿
    100
  • X 旗下 Grok 推出即时语音搜索功能 向 Google 发起挑战?

    近日,X 平台的人工智能助手 Grok 正式上线“即时语音搜索”功能,用户现在可通过语音直接提问,触发实时网络检索,并迅速获得整合后的精准答复。这项新能力意在优化信息查询流程,推动人机互动向更自然、高效的形态发展。 根据官方说明与实际用户体验,Grok 的语音搜索实现了“说话即搜、即时回应”的流畅体…

    2026年9月23日
    100
  • Java JUnit assertThrows 与异常消息比对:避免常见陷阱

    本教程深入探讨在 Java JUnit 中使用 assertThrows 进行异常测试时常见的 assertEquals 误用问题。它详细解释了为何不能直接将期望的字符串消息与捕获到的异常对象进行比对,并提供了正确的解决方案:通过 e.getMessage() 获取异常消息进行精确断言,确保测试的准…

    2026年9月23日
    000
  • PHP:根据条件动态禁用表格中的按钮

    本文旨在解决在PHP中,根据表格行中两列的值是否相等,动态禁用对应按钮的问题。通过修改循环遍历数据并生成HTML表格的代码,在生成按钮时增加条件判断,实现当mi_name列和item_name列的值相等时,禁用该行的按钮。文章提供两种实现方式,并附带代码示例,帮助开发者快速实现此功能。 在PHP中动…

    2026年9月23日
    100
  • 漫蛙漫画PC电脑版官网入口 漫蛙高清漫画免VIP沉浸式阅读体验

    您在寻找漫蛙漫画的pc电脑版官网入口吗?为了在电脑大屏幕上获得最佳的高清、免vip沉浸式阅读体验,本文将为您分享最新的官网入口。当常用链接失效时,掌握备用入口是关键。目前,最适合pc端浏览的官网入口是 https://manwa.me(推荐非大陆地区),以及一个备用高清漫画网址 https://fu…

    2026年9月23日
    400
  • safari浏览器如何导入Netscape格式的书签文件_safari浏览器导入Netscape书签方法

    Safari无法直接读取Netscape格式书签时,可通过HTML文件转换、第三方工具修复或借助Chrome/Firefox中转导入。首先确认书签文件含标准结构,尝试直接导入Safari;若失败,使用Linkman Lite等工具修复格式后导入;或通过Chrome先行导入再导出标准HTML文件,最后…

    2026年9月23日
    000
  • VSCode如何通过AI优化内存使用 VSCode智能内存分析调试插件

    ai并不能直接优化vscode的内存占用,而是通过赋能智能化的内存分析调试插件,间接提升vscode的运行效率和开发体验;2. 这类插件通过采集堆快照、cpu性能数据、gc日志和扩展资源消耗等运行时信息,结合ai的模式识别与异常检测能力,精准识别内存泄漏、未清理的事件监听器、循环引用等问题;3. a…

    2026年9月23日
    200
  • PHP容器与依赖注入怎么理解_PHP中DI容器概念与Pimple等库应用

    依赖注入通过外部传入依赖解耦代码,容器如Pimple集中管理对象创建与依赖解析,提升可测试性与维护性,适用于中小型项目。 PHP中的容器和依赖注入(Dependency Injection,简称DI)是现代开发中解耦代码、提升可测试性和可维护性的核心技术。理解它们的关键在于掌握“控制反转”(Inve…

    2026年9月23日
    100
  • 悟空浏览器提示“网络错误”无法上网怎么办_悟空浏览器网络错误解决方法

    首先检查网络连接是否正常,确认Wi-Fi或移动数据已开启并信号良好;尝试切换网络类型或重启路由器。若问题仍存在,进入设置清除悟空浏览器缓存与数据,排除因缓存堆积导致的加载失败。接着可更改DNS为8.8.8.8和114.114.114.114以提升解析成功率。同时禁用浏览器插件与扩展功能,避免其干扰网…

    2026年9月23日
    100
  • VS Code算法实战:竞赛编程与调试环境搭建

    首先安装编程语言环境及VS Code扩展,如C/C++、Code Runner和LeetCode;接着配置Code Runner支持编译运行与输入重定向;最后通过代码片段提升编码速度,形成高效竞赛开发环境。 在竞赛编程中,高效的开发环境能大幅提升编码速度与调试效率。VS Code凭借轻量、可扩展和强…

    2026年9月23日
    000
  • 字节入局,AR眼镜掀起新“风口”?

    近日,关于老凤祥与字节跳动合作推出AI眼镜的消息在网络上引发热议。据相关媒体报道,老凤祥计划联合字节跳动旗下的火山引擎共同开发多款AI眼镜,并由豆包大模型提供技术支持,预计将在今年7月正式发布。 对此,6月12日,火山引擎方面进行了澄清。其负责人表示,并未有与老凤祥合作研发AI智能眼镜的计划。而豆包…

    2026年9月23日
    000
  • mysql安装完如何连接java mysql jdbc驱动配置教程

    mysql安装完如何连接java mysql jdbc驱动配置教程mysql安装完如何连接java mysql jdbc驱动配置教程mysql安装完如何连接java mysql jdbc驱动配置教程mysql安装完如何连接java mysql jdbc驱动配置教程

    下载并导入jdbc驱动包;2. 正确配置数据库连接信息;3. 加载驱动并建立连接。使用java连接mysql的关键在于配置好jdbc驱动,首先去mysql官网下载对应版本的mysql-connector-java.jar包并导入项目,普通项目放入lib目录并添加为库,maven项目则在pom.xml…

    2026年9月23日 • 用户投稿
    200
  • 在无Maven或Eclipse环境下手动构建Java Web应用WAR包的教程

    本教程详细介绍了如何在不依赖Maven或Eclipse等集成开发环境的情况下,为Java Web应用程序手动生成WAR(Web Application Archive)文件。文章首先阐述了WAR文件的基本结构,随后通过一个Ant构建脚本的实例,指导读者完成从源代码编译、文件组织到最终WAR包生成的全…

    2026年9月23日
    000
  • AdobePhotoshop的AI混合工具怎么用?掌握智能图像编辑的教程

    Photoshop的AI混合工具以生成式填充和神经网络滤镜为代表,通过语义理解实现智能图像融合。生成式填充可依据文本提示添加、移除或扩展内容,自动匹配光影与纹理;神经网络滤镜如和谐化则优化颜色与光照匹配。与传统基于像素计算的混合模式不同,AI工具理解图像内容,实现“生成并融合”。使用时需精准输入英文…

    2026年9月23日
    100
  • PHP多维数组重构:按指定键值分组数据

    本文将详细介绍如何在PHP中将扁平化的关联数组列表重构为多维数组,核心思路是根据数组中某个特定键(例如 object_type)的值进行分组,将具有相同键值的所有子数组归集到同一个父级键下,从而实现数据的层次化组织,提高数据的可读性和管理效率。 引言:数据重构的需求 在PHP开发中,我们经常会遇到需…

    2026年9月23日
    000
  • 解决 Conda 环境中 Java 版本冲突的策略

    本文旨在解决 Conda 环境中 Java 版本激活不正确的问题。当用户尝试在 Conda 环境中指定特定 Java 版本(如 OpenJDK 8)时,系统可能仍激活旧的或错误的 Java 版本。教程将详细分析问题根源,并提供一种通过精确指定 Java 包名来确保 Conda 环境正确管理 Java…

    2026年9月23日
    000
  • Windows安装过程中蓝屏INACCESSIBLE_BOOT_DEVICE怎么办?

    1、蓝屏“INACCESSIBLE_BOOT_DEVICE”通常因SATA模式不匹配或驱动缺失导致;2、进入BIOS将SATA模式从RAID改为AHCI可解决兼容性问题;3、安装时加载主板存储控制器驱动以识别NVMe或RAID磁盘;4、使用diskpart命令清理磁盘并转换为GPT(UEFI)或MB…

    2026年9月23日
    000
  • 谷歌为 Gemini CLI 带来扩展功能

    谷歌旗下的 AI 编程助手 Gemini CLI 最近推出了名为“扩展”的全新功能。官方表示,这一更新让用户能够“接入常用工具,并定制属于自己的 AI 命令行体验”。现在,任何开发者都可以发布扩展程序,无需经过谷歌的审核批准即可上线使用。 目前扩展库中已提供超过 50 款扩展,涵盖多种实用场景。例如…

    2026年9月23日
    000

发表回复

登录后才能评论
关注微信