window.requestAnimationFrame(callback),接受一个函数作为参数,在浏览器下次重绘前执行,大约是17毫秒(1000ms的60分之一,60HZ)左右执行一次(不同显示器刷新频率不同,75HZ,120HZ等刷新的间隔更短)。
rAF主要是做动画的,好处是不卡顿,动画也可以用setTimeout函数模拟,但是会卡顿。
为什么定时器会卡,而requestAnimationFrame不会卡
- 定时器的回调函数,会受到js的事件队列宏任务、微任务影响,可能设定的是17毫秒执行一次,但是实际上这次是17毫秒、下次21毫秒、再下次13毫秒执行,所以并不是严格的卡住了这个60HZ的时间,会给人卡顿的感觉
为何requestAnimationFrame不会卡
- rAF能够做到,精准严格的卡住显示器刷新的时间,比如普通显示器60HZ它会自动对应17ms执行一次,比如高级显示器120HZ,它会自动对应9ms执行一次。
rAF只会执行一次,想要多次执行,需要递归调用。
- rAF也有返回值,返回值是一个整数,主要是定时器的身份证标识,可以使用 window.cancelAnimationFrame(返回值)来取消回调函数执行,相当于定时器中的clearTimeout()。
应用-跳转顶部动画
<div class="test"></div>
<button id="btn-jump">跳转顶部</button>
<script>
var jumpBtn = document.getElementById("btn-jump")
var jumpFn1 = null
var jumpFn = () => {
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
if(scrollTop > 0) {
jumpFn1 = window.requestAnimationFrame(jumpFn)
window.scrollTo(0, scrollTop - scrollTop / 10) //跳转y坐标根据需求效果更改
}
}
jumpBtn.addEventListener("click",jumpFn)
</script>
应用-进度条
<style>
.c-box{
margin: 10px auto;
width: 400px;
height: 5px;
border-radius: 5px;
background-color: #ccc;
}
.c-pr {
width: 0;
height: 100%;
background: #00a1ff;
border-radius: 5px;
}
</style>
<div class="c-box">
<div class="c-pr" id="c-pr"></div>
</div>
<p class="c-txt" id="c-txt">进度:0</p>
<button id="c-start">开始</button>
<script>
var cBtn = document.getElementById("c-start")
var cPr = document.getElementById("c-pr")
var cTxt = document.getElementById("c-txt")
var cWidth = 0
var cFn = null
var goFn = () => {
if(cWidth <= 398) {
cWidth += 2
cPr.style.width = cWidth + 'px'
cFn = window.requestAnimationFrame(goFn)
cTxt.innerText = '进度:' + ((cWidth / 400) * 100).toFixed(2) + '%'
console.log(111);
} else {
window.cancelAnimationFrame(cFn)
cFn = null
cWidth = 0
}
}
var toggleFn = () => {
if(cFn) {
window.cancelAnimationFrame(cFn)
cFn = null
} else {
goFn()
}
}
cBtn.addEventListener("click",toggleFn)
</script>