提升用户体验之requestAnimationFrame实现前端动画

小御姐@stella 2024-07-23 08:03:03 阅读 59

1)requestAnimationFrame是什么?
1.MDN官方解释

在这里插入图片描述

2.解析这段话:

1、那么浏览器重绘是指什么呢?

——大多数电脑的显示器刷新频率是60Hz,1000ms/60=16.66666667ms的时间刷新一次

2、重绘之前调用指定的回调函数更新动画?

——requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中 紧跟随浏览器的刷新频率 去完成操作。

2)基础用法

<code><script setup>

let animationRef

const goStart = () => {

const cb = () => {

// 写入DOM 操作会在每一次浏览器刷新之前执行❤

requestAnimationFrame(cb)

}

// 开启动画

animationRef = requestAnimationFrame(cb)

}

const goEnd = () => {

// 取消动画

cancelAnimationFrame(animationRef)

}

</script>

3)requestAnimationFrame的优点
1.传统实现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

在这里插入图片描述

其实就是当线程忙碌时,定时器会等待线程队列中的任务执行后再执行。

所以定时器动画,视觉上看来,就是一盹一盹…的效果。

2.requestAnimationFrame

而requestAnimationFrame由浏览器专门为动画提供的 API,就是为了解决这类问题,提升用户体验的。

且我们切换到其他页面时,requestAnimationFrame会暂停下来,直到我们回到该页面后,动画会从暂停的位置继续执行。

3.应用场景

在这里插入图片描述

会用一定卡顿,可以到我的github下载代码运行看效果。

https://github.com/wwaini/tao-vue3/tree/release240625

<code><template>

<div class="btn">code>

<el-button @click="goStart">开始</el-button>code>

<el-button @click="goEnd">停止</el-button>code>

</div>

<div class="a-box">定时器</div>code>

<div class="b-box">requestAnimationFrame</div>code>

</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">code>

.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>

4)requestAnimationFrame兼容性

对比



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。