requestAnimationFrame是什么
MDN官方解释
解析这段话:
1、那么浏览器重绘是指什么呢?
——大多数电脑的显示器刷新频率是60Hz,1000ms/60=16.66666667ms的时间刷新一次
2、重绘之前调用指定的回调函数更新动画?
——requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中 紧跟随浏览器的刷新频率 去完成操作。
基础用法
<script setup>
let animationRef
const goStart = () => {
const cb = () => {
// 写入DOM 操作会在每一次浏览器刷新之前执行❤
requestAnimationFrame(cb)
}
// 开启动画
animationRef = requestAnimationFrame(cb)
}
const goEnd = () => {
// 取消动画
cancelAnimationFrame(animationRef)
}
</script>
requestAnimationFrame的优点
传统实现JS动画
通常情况下,实现动画能使用css实现的就使用css,不能的css实现的再使用JS实现。
我们实现JS动画,会使用setTimeout和setInterval。
而setTimeout和setInterval的使用是存在问题的,导致丢帧。
一个是,间隔时间不好确定,前面也提到大多数电脑的显示器刷新频率是60Hz,1000ms/60(这里对比使用17ms),那么定时器的间隔时间设置过长或者过短都无法匹配上刷新频率。
一个是,MDN指出定时器实际延长时间比设定值长一些。常见的几种情况,嵌套超时、非活动标签的超时、追踪型脚本的节流、超时延迟等…
这里就不过多赘述,可以到以下链接阅读 https://developer.mozilla.org/zh-CN/docs/Web/API/setTimeout
所以定时器动画,视觉上看来,就是一盹一盹…的,而requestAnimationFrame就是为了解决这类问题,提升用户体验的。
应用场景
会用一定卡顿,可以到我的github下载代码运行看效果。
https://github.com/lssChaseDream/tao-vue3/tree/release240625
<template>
<div class="btn">
<el-button @click="goStart">开始</el-button>
<el-button @click="goEnd">停止</el-button>
</div>
<div class="a-box">定时器</div>
<div class="b-box">requestAnimationFrame</div>
</template>
<script setup>
import { ref } from 'vue'
let leftNum = ref(0)
let flag = ref(false) // 定时器动画停止标识
let timmer // 定时器
let animationRef // requestAnimationFrame存储
// 定时器动画事件
const goAStart = () => {
let dom = document.getElementsByClassName('a-box')
dom[0].style.width = '10px'
timmer = setInterval(() => {
leftNum.value = parseInt(dom[0].style.width)
if (leftNum.value > 800 || flag.value) {
clearInterval(timmer)
} else {
dom[0].style.width = (leftNum.value + 3) + 'px'
console.log(dom[0].style.width);
}
}, 17);
}
const goAEnd = () => {
clearInterval(timmer)
}
// requestAnimationFrame动画事件
const goBStart = () => {
let dom = document.getElementsByClassName('b-box')
dom[0].style.width = '10px'
const cb = () => {
leftNum.value = parseInt(dom[0].style.width)
if (leftNum.value > 800) {
} else {
dom[0].style.width = (leftNum.value + 3) + 'px'
console.log(dom[0].style.width);
animationRef = requestAnimationFrame(cb)
}
}
requestAnimationFrame(cb)
}
const goBEnd = () => {
cancelAnimationFrame(animationRef)
}
const goEnd = () => {
goAEnd()
goBEnd()
}
const goStart = () => {
goAStart()
goBStart()
}
</script>
<style scoped lang="scss">
.btn {
text-align: center;
margin-bottom: 20px;
}
.a-box {
width: 20px;
height: 80px;
background-color: pink;
position: absolute;
}
.b-box {
width: 20px;
height: 80px;
background-color: blueviolet;
color: #fff;
position: absolute;
top: 120px;
}
</style>