首页 > 其他分享 >还在使用定时器吗?试试requestAnimationFrame

还在使用定时器吗?试试requestAnimationFrame

时间:2024-12-12 10:59:21浏览次数:3  
标签:rafId 定时器 const 试试 requestAnimationFrame value js init

目录

基本认识

简介

停止

自动停止

手动停止

使用场景

js动画


前言:相信能点进来看我博客的小伙子们,应该都是前端吧。那想必是知道定时器或者requestAnimationFrame 吧。这里说的重点呢就是 requestAnimationFrame 。如果你对它并不了解,那我下文中也会对它进行补充说明的。

基本认识

简介

这是MDN对其的介绍:

window.requestAnimationFrame() 方法会告诉浏览器你希望执行一个动画。它要求浏览器在下一次重绘之前,调用用户提供的回调函数。

对回调函数的调用频率通常与显示器的刷新率相匹配。虽然 75hz、120hz 和 144hz 也被广泛使用,但是最常见的刷新率还是 60hz(每秒 60 个周期/帧)。为了提高性能和电池寿命,大多数浏览器都会暂停在后台选项卡或者隐藏的 <iframe> 中运行的 requestAnimationFrame()

MDN对requestAnimationFrame的介绍

但是我认为,大家认识requestAnimationFrame很多人都是通过 Three.js 的。在使用 Three.js 中基本都会使用 requestAnimationFrame 。

代码案例: 

    function init() {
      console.log('您好');
      requestAnimationFrame(init)
    }
    requestAnimationFrame(init)

requestAnimationFrame会一直递归调用执行,并且调用的频率通常是与当前显示器的刷新率相匹配(这也是这个API核心优势),例如屏幕120hz1秒执行120次。

而且如果使用的是定时器实现此功能是无法适应各种屏幕帧率的。

停止

自动停止

当我们把使用了requestAnimationFrame的页面切换到后台运行时,requestAnimationFrame会暂停执行,切换回来后会马上提着执行。从某种角度来说,它自带性能优化的功能。

手动停止

那么这个函数是递归的,那如何手动取消这个无限递归的requestAnimationFrame呢?那让然是使用cancelAnimationFrame。例如:

  let myReq;
  function init(val) {
    console.log('您好');
    myReq = requestAnimationFrame(init);
  }
  requestAnimationFrame(init);

  function stop() {
    cancelAnimationFrame(myReq);
  }

看到这里,相信大家对这个requestAnimationFrame有了一定的了解。 

使用场景

js动画

requestAnimationFrame比定时器更好制作出丝滑的js动画,相信很多封装的js库的底层也都会用requestAnimationFrame。

如果大家在制作js动画的时候,用上它肯定绝绝子好吧。

例如:

代码如下: 

<template>
  <div class="container" ref="scrollRef">
    <div v-for="(item, index) in items" :key="index" class="item">
      {{ item }}
    </div>
    <div v-if="loading" class="loading">数据加载中...</div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';

const loading = ref(false);
let rafId: number | null = null;
// 数据列表
const items = ref<string[]>(Array.from({ length: 50 }, (_, i) => `Test ${i + 1}`));

// 滚动容器
const scrollRef = ref<HTMLElement | null>(null);

// 模拟一个异步加载数据效果
const moreData = () => {
  return new Promise<void>((resolve) => {
    setTimeout(() => {
      const newItems = Array.from({ length: 50 }, (_, i) => `Test ${items.value.length + i + 1}`);
      items.value.push(...newItems);
      resolve();
    }, 1000);
  });
};

// 检查是否需要加载更多数据
const checkScrollPosition = () => {
  if (loading.value) return;
  const container = scrollRef.value;
  if (!container) return;
  const scrollTop = container.scrollTop;
  const clientHeight = container.clientHeight;
  const scrollHeight = container.scrollHeight;
  if (scrollHeight - scrollTop - clientHeight <= 100) {
    startLoading();
  }
};

// 加载数据
const startLoading = async () => {
  loading.value = true;
  await moreData();
  loading.value = false;
};

// 监听滚动事件
const handleScroll = () => {
  console.log('滚动事件触发啦');
  if (rafId !== null) {
    window.cancelAnimationFrame(rafId);
  }
  rafId = window.requestAnimationFrame(checkScrollPosition);
};

// 添加滚动事件监听器
onMounted(() => {
  if (scrollRef.value) {
    scrollRef.value.addEventListener('scroll', handleScroll);
  }
});

// 移除相关事件
onUnmounted(() => {
  if (rafId !== null) {
    window.cancelAnimationFrame(rafId);
  }
  if (scrollRef.value) {
    scrollRef.value.removeEventListener('scroll', handleScroll);
  }
});
</script>

<style scoped>
.container {
  padding: 20px;
  max-width: 800px;
  overflow-y: auto;
  margin: 0 auto;
  height: 600px; 
}

.item {
  border-bottom: 1px solid #ccc;
  padding: 10px;
}

.loading {
  padding: 10px;
  color: #999;
  text-align: center;
}
</style>

除了上面的小示例其它非常多地方都可以用到requestAnimationFrame去优化性能,比较常见的例如游戏开发、各种动画效果和动态变化的布局等等。 

标签:rafId,定时器,const,试试,requestAnimationFrame,value,js,init
From: https://blog.csdn.net/weixin_63443072/article/details/144415543

相关文章

  • GLB文件如何转换成3DTiles文件?试试这款免费GIS工具箱
    概述在现代地理信息系统(GIS)应用中,三维可视化已成为不可或缺的一部分。特别是在城市规划、数字孪生和智能建筑等领域,三维模型数据的高效管理和发布需求日益增加。GLB是一种轻量级的3D模型文件格式,因其高效的存储特性广泛应用。而将GLB转换为3DTiles格式,则是将三维模型应用于GIS可......
  • STM32中使用低功耗定时器延时
    此篇文章在2022年5月19日被记录上文说了STM32L4的几种低功耗模式,将其应用起来作为一个低功耗的延时方案。为什么使用低功耗定时器,在追求长时间续航时,单片机有时需要切换到低功耗模式或者停止模式下,在这种模式下,系统主时钟关闭,有一些依赖于系统主时钟的应用程序,可能会发生出现......
  • STM32单片机芯片与内部13 TIM-通用定时器TIM2345 高级定时器TIM18-定时计数功能、库函
    目录一、通用定时器库函数工程模板1、TIM_TimeBaseInitTypeDef2、时钟3、初始化4、中断服务函数二、通用定时器库函数API1、初始化封装2、中断服务函数封装三、高级定时器库函数工程模板1、TIM_TimeBaseInitTypeDef2、时钟3、初始化4、中断服务函数四、高级定时......
  • STM32单片机芯片与内部12 TIM-基本定时器TIM67 -定时计数功能、库函数配置、HAL库配置
    目录一、功能二、库函数工程模板1、NVIC_InitTypeDef与TIM_TimeBaseInitTypeDef2、时钟使能3、初始化4、清除中断5、开启/关闭中断6、使能/失能计数器三、库函数API1、初始化的封装2、中断服务函数四、HAL库工程模板1、TIM_HandleTypeDef2、TIM_MasterConfigType......
  • 如何汇报更有条理?试试结构化汇报
    来一个小思考题:假设你是一个项目团队Leader,在每周的早会上需要听取20多名成员的周工作总结,并在此基础上,对团队整体工作做出总结和点评。员工A和B分别这样汇报:汇报A:“呃……我这周做了很多事,比如和客户沟通了几次,然后做了些文档整理,还有……哦,对,还有一次会议。我感觉工作挺多的,......
  • 用了ChatGPT还是搞不定论文写作?试试这些提示词!
    在学术写作中,论文的写作过程通常包括选题、文献综述、数据分析、正文写作、引用管理等多个步骤。每个环节都需要大量的时间和精力投入,特别是在逻辑构建和内容组织方面。借助ChatGPT的智能生成能力,可以快速生成初稿、优化语言、进行资料查询,极大地提升写作效率。今天的分享将为......
  • 7-164 试试手气
    我们知道一个骰子有6个面,分别刻了1到6个点。下面给你6个骰子的初始状态,即它们朝上一面的点数,让你一把抓起摇出另一套结果。假设你摇骰子的手段特别精妙,每次摇出的结果都满足以下两个条件:1、每个骰子摇出的点数都跟它之前任何一次出现的点数不同;2、在满足条件1的前......
  • 定时器实现之红黑树(二)
    1.概述    书接上回定时器实现之最小堆(一),今天采用红黑树来作为定时器的容器,组织定时器的定时节点。2.为什么红黑树能用来实现定时器         前面一章提到过,能用来实现定时器的容器的基本要求就是有序,而红黑树的中序遍历就是有序的,如下图:    并......
  • 基于链表的定时器管理(三)
    5.启动定时器(timer_start)(工作中经常用到)timer_start函数接收定时器的过期时间和回调函数,并将定时器节点插入到定时器链表中。inttimer_start(timer_list_t*timer_list,timer_node_t*timer_node,UINT32expire_time,......
  • 面试考题:定时器底层逻辑
    前言让我们回想一下关于定时器的内容,我们只知道,他是在我们设置的时间后才异步执行的程序。可在面试时回答这个就够了吗?那当然是不够的。本文将带你深入了解定时器底层定义我们先了解什么是定时器。在JavaScript中,定时器是一种用于延迟执行代码或定期执行代码的机制。它......