JS中requestAnimationFrame函数的原理和应用场景

requestAnimationFrame 的原理

requestAnimationFrame 是浏览器提供的一个 API,用于更高效地实现动画。它的核心原理是让浏览器在下次重绘(repaint)之前执行指定的回调函数,从而确保动画的流畅性,并避免不必要的性能开销。

核心特点
  1. 节能高效
    • 只有在页面处于激活状态时,requestAnimationFrame 才会运行,页面不可见时会暂停动画,从而节省系统资源。
  2. 与屏幕刷新同步
    • 回调函数的执行频率与显示器的刷新率(通常为60Hz,即每秒60帧)保持一致,避免了定时器(如 setTimeoutsetInterval)可能导致的帧数不均匀或动画卡顿问题。

使用方法

基本语法
let animationId = requestAnimationFrame(callback);
  • 参数
    • callback:一个函数,在下一次重绘前会被执行。
  • 返回值
    • 一个 ID,可以通过 cancelAnimationFrame 来取消。
完整示例
let startTime = null;

function step(timestamp) {
  if (!startTime) startTime = timestamp; // 初始化起始时间
  const progress = timestamp - startTime; // 计算动画运行时间

  // 在页面中移动一个元素
  const element = document.getElementById("animatedBox");
  element.style.transform = `translateX(${Math.min(progress / 10, 200)}px)`; // 限制最大位移

  if (progress < 2000) { // 控制动画时长为 2000ms
    requestAnimationFrame(step); // 继续下一帧动画
  }
}

requestAnimationFrame(step);
取消动画
const animationId = requestAnimationFrame(callback);
// 取消动画
cancelAnimationFrame(animationId);

应用场景

1. 页面动画
  • 创建基于帧的流畅动画,如滚动、移动、缩放等。
  • 例如,制作平滑的滚动效果:
function smoothScroll(targetPosition, duration) {
  const startPosition = window.scrollY;
  const distance = targetPosition - startPosition;
  let startTime = null;

  function animation(currentTime) {
    if (!startTime) startTime = currentTime;
    const elapsedTime = currentTime - startTime;

    const easeInOutQuad = (t, b, c, d) => {
      t /= d / 2;
      if (t < 1) return c / 2 * t * t + b;
      t--;
      return -c / 2 * (t * (t - 2) - 1) + b;
    };

    const scrollPosition = easeInOutQuad(elapsedTime, startPosition, distance, duration);
    window.scrollTo(0, scrollPosition);

    if (elapsedTime < duration) {
      requestAnimationFrame(animation);
    }
  }

  requestAnimationFrame(animation);
}

// 使用:
smoothScroll(500, 1000); // 滚动到500px位置,用时1000ms
2. 游戏动画
  • 在 HTML5 Canvas 或 WebGL 中,与游戏的帧刷新同步。
  • 例如,一个简单的球移动动画:
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

let x = 50, y = 50, dx = 2, dy = 2;

function drawBall() {
  ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空画布
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI * 2); // 画圆
  ctx.fillStyle = "blue";
  ctx.fill();
  ctx.closePath();
}

function update() {
  drawBall();
  x += dx;
  y += dy;

  if (x + dx > canvas.width || x + dx < 0) dx = -dx;
  if (y + dy > canvas.height || y + dy < 0) dy = -dy;

  requestAnimationFrame(update);
}

update();
3. 数据可视化
  • 动态更新图表、数据仪表盘等,如基于 D3.jsThree.js 的场景中实现平滑更新。
4. 防止页面卡顿
  • 适用于实现一些逐帧的操作,比如逐帧加载图像。

setIntervalrequestAnimationFrame 的区别

特性setTimeoutrequestAnimationFrame
频率控制不保证与刷新率同步,可能导致丢帧与刷新率一致,通常为 60FPS
节能页面隐藏时仍在运行,浪费资源页面隐藏时自动暂停
使用复杂度更简单,直接延时调用更适合动画,需自行管理帧逻辑
性能优化不够流畅,容易卡顿更流畅,避免视觉卡顿

注意事项

  1. 节流控制
    • 避免在动画中进行过多计算或 DOM 操作,影响性能。
  2. 兼容性
    • 现代浏览器都支持,但可以使用 Polyfill 以兼容旧版本浏览器:
      window.requestAnimationFrame = window.requestAnimationFrame || function(callback) {
        return setTimeout(callback, 1000 / 60);
      };
      

通过合理使用 requestAnimationFrame,可以实现流畅、节能的动画效果,非常适合高性能要求的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/941352.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

什么是 DevOps 自动化?

DevOps 自动化是一种现代软件开发方法&#xff0c;它使用工具和流程来自动化任务并简化工作流程。它将开发人员、IT 运营和安全团队聚集在一起&#xff0c;帮助他们有效协作并交付可靠的软件。借助 DevOps 自动化&#xff0c;组织能够处理重复性任务、优化流程并更快地将应用程…

帝国CMS:如何去掉帝国CMS登录界面的认证码登录

如果在安装的时候&#xff0c;不小心选中了认证码选项&#xff0c;那么后面登录帝国后台都会要求输入认证码才能登录&#xff0c;如何去除这个设置呢&#xff0c;笔者以古诗词网 www.gushichi.com为例&#xff0c;为大家举例说明&#xff01; 去除步骤如下&#xff1a; 1.前往…

4.2V单节锂电池充电电路(TP4056)、USB与锂电池切换电路分享

一、充电原理图 1、连接说明 BAT_VCC和BAT_GND连接电池 VUSB和GND连接USB电源 2、芯片介绍 a、DW01 DW01芯片是一种电池管理保护芯片&#xff0c;主要用于锂离子电池的保护和管理。DW01芯片具有以下特点&#xff1a; 电池电压保护&#xff1a;DW01芯片可以监测和保护电池的…

ChatGPT生成接口文档实践案例(二)

不难发现&#xff0c;两个方案都出色地完成了接口文档的生成&#xff0c;但笔者更喜欢Response 2的表达&#xff0c;因为其描述更加全面。 还可以让ChatGPT生成符合OpenAPI 3.0规范的接口文档&#xff0c;以便于项目相关成员阅读&#xff0c;如图5-13所示。 为什么要生成OpenAP…

MFC用List Control 和Picture控件实现界面切换效果

添加List Control 和Picture控件 添加 3个子窗体 把子窗体边框设置为None, 样式设为Child 声明 CListCtrl m_listPageForm;void ShowForm(int nIndex);void CreatFormList();void CMFCApplication3Dlg::DoDataExchange(CDataExchange* pDX) {CDialogEx::DoDataExchange(pDX);DD…

JavaWeb Servlet的反射优化、Dispatcher优化、视图(重定向)优化、方法参数值获取优化

目录 1. 背景2. 实现2.1 pom.xml2.2 FruitController.java2.3 DispatcherServlet.java2.4 applicationContext.xml 3. 测试 1. 背景 前面我们做了Servlet的一个案例。但是存在很多问题&#xff0c;现在我们要做优化&#xff0c;优化的步骤如下&#xff1a; 每个Fruit请求都需…

frp内网穿透云服务器。云服务器映射多个家庭局域网内网端口。家庭Windows主机内网运行多个web程序

这篇文章最终要实现的效果是&#xff0c;把云服务器的公网IP绑定到自己本地局域网上的主机一样的效果。相当于局域网主机有了一个自己的公网IP地址。 FRP (Fast Reverse Proxy) 是一个用 Go 语言编写的高性能反向代理应用程序&#xff0c;主要用于内网穿透。它允许位于 NAT 或…

windos 安装docker

文章目录 安装1.下载安装包2.双击安装软件 验证修改国内镜像地址FAQDocker Engine stopped 小结 安装 1.下载安装包 到官网下载适配的安装包&#xff1a;https://www.docker.com/products/docker-desktop/ 2.双击安装软件 选择ok 等待安装依赖 安装完成以后会重启电脑&am…

【已解决】黑马点评项目Redis版本替换过程中误删数据库后前端显示出现的问题

为了实现基于Redis的Stream结构作为消息队列&#xff0c;实现异步秒杀下单的功能&#xff0c;换Redis版本 Redis版本太旧了&#xff0c;所以从3.2.1换成了5.0.14 此时犯了一个大忌&#xff0c;因为新的Redis打开后&#xff0c;没有缓存&#xff0c;不知道出了什么问题&#xf…

Odoo 免费开源 ERP:通过 JavaScript 创建对话框窗口的技术实践分享

作者 | 老杨 出品 | 上海开源智造软件有限公司&#xff08;OSCG&#xff09; 概述 在本文中&#xff0c;我们将深入研讨如何于 Odoo 18 中构建 JavaScript&#xff08;JS&#xff09;对话框或弹出窗口。对话框乃是展现重要讯息、确认用户操作以及警示用户留意警告或错误的行…

Tool之Excalidraw:Excalidraw(开源的虚拟手绘风格白板)的简介、安装和使用方法、艾米莉应用之详细攻略

Tool之Excalidraw&#xff1a;Excalidraw(开源的虚拟手绘风格白板)的简介、安装和使用方法、艾米莉应用之详细攻略 目录 Excalidraw 简介 1、Excalidraw 的主要特点&#xff1a; Excalidraw 安装和使用方法 1、Excalidraw的安装 T1、使用 npm 安装&#xff1a; T2、使用 …

探索CSDN博客数据:使用Python爬虫技术

探索CSDN博客数据&#xff1a;使用Python爬虫技术 在数字化的浪潮中&#xff0c;数据的获取与分析变得日益关键。CSDN作为中国领先的IT社区和服务平台&#xff0c;汇聚了海量的技术博客与文章&#xff0c;成为一座蕴藏丰富的数据宝库。本文将引领您穿梭于Python的requests和py…

【蓝桥杯选拔赛真题96】Scratch风车旋转 第十五届蓝桥杯scratch图形化编程 少儿编程创意编程选拔赛真题解析

目录 scratch风车旋转 一、题目要求 编程实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 1、思路分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 5、python资料 scratc…

LeetCode:222.完全二叉树节点的数量

跟着carl学算法&#xff0c;本系列博客仅做个人记录&#xff0c;建议大家都去看carl本人的博客&#xff0c;写的真的很好的&#xff01; 代码随想录 LeetCode&#xff1a;222.完全二叉树节点的数量 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二…

CNN和Transfomer介绍

文章目录 CNN和Transfomer介绍CNN和Transfomer的区别1. **基本概念**2. **数据处理方式**3. **模型结构差异**4. **应用场景区别** 自注意力机制1. **自注意力机制的概念**2. **自注意力机制的实现步骤**3. **自注意力机制的优势** Transformer结构组成1. **多头注意力层&#…

【数据结构练习题】栈与队列

栈与队列 选择题括号匹配逆波兰表达式求值出栈入栈次序匹配最小栈设计循环队列面试题1. 用队列实现栈。[OJ链接](https://leetcode.cn/problems/implement-stack-using-queues/solutions/)2. 用栈实现队列。[OJ链接](https://leetcode.cn/problems/implement-queue-using-stack…

python 定时任务管理封装

主逻辑代码 # -*- coding: utf-8 -*- # import apscheduler import pandas as pd from datetime import datetime # 导入调度器&#xff0c;此处使用BackgroundScheduler阻塞调度器 from apscheduler.schedulers.background import BackgroundScheduler # 导入触发器&#xf…

MaxKB基于大语言模型和 RAG的开源知识库问答系统的快速部署教程

1 部署要求 1.1 服务器配置 部署服务器要求&#xff1a; 操作系统&#xff1a;Ubuntu 22.04 / CentOS 7.6 64 位系统CPU/内存&#xff1a;4C/8GB 以上磁盘空间&#xff1a;100GB 1.2 端口要求 在线部署MaxKB需要开通的访问端口说明如下&#xff1a; 端口作用说明22SSH安装…

LCAN-FOBR设备在风力发电项目的消防通讯中的使用

LCAN-FOBR设备在风力发电项目的消防通讯中的使用 在风力发电项目中&#xff0c;所有的风机内部的状态都需要能够在中控室备被监控到&#xff0c;不论是风机的工作状态还是风机内部的消防状态&#xff0c;以便中控室的工作人员都够根据观测到的信息及时的做出反应&#xff0c;避…

Linux扩展——shell编程

前置&#xff1a;Linux基础及命令复习 目录 shell概述Shell脚本入门案例 sh bash ./ . source 变量系统预定义变量 $HOME $PWD $SHELL等自定义变量 unset readonly补充&#xff1a;开启子Shell进程的常见方法 (...) $(...) ... <(...) >(...) 特殊变量 $n $# $* $ $&…