目录
前言:相信能点进来看我博客的小伙子们,应该都是前端吧。那想必是知道定时器或者requestAnimationFrame 吧。这里说的重点呢就是 requestAnimationFrame 。如果你对它并不了解,那我下文中也会对它进行补充说明的。
基本认识
简介
这是MDN对其的介绍:
window.requestAnimationFrame()
方法会告诉浏览器你希望执行一个动画。它要求浏览器在下一次重绘之前,调用用户提供的回调函数。对回调函数的调用频率通常与显示器的刷新率相匹配。虽然 75hz、120hz 和 144hz 也被广泛使用,但是最常见的刷新率还是 60hz(每秒 60 个周期/帧)。为了提高性能和电池寿命,大多数浏览器都会暂停在后台选项卡或者隐藏的 <iframe> 中运行的
requestAnimationFrame()
。
但是我认为,大家认识requestAnimationFrame很多人都是通过 Three.js 的。在使用 Three.js 中基本都会使用 requestAnimationFrame 。
代码案例:
function init() {
console.log('您好');
requestAnimationFrame(init)
}
requestAnimationFrame(init)
requestAnimationFrame
会一直递归调用执行,并且调用的频率通常是与当前显示器的刷新率相匹配
(这也是这个API
核心优势),例如屏幕120hz
就1
秒执行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
去优化性能,比较常见的例如游戏开发、各种动画效果和动态变化的布局等等。