window.requestAnimationFrame(callback),接受一個(gè)函數(shù)作為參數(shù),在瀏覽器下次重繪前執(zhí)行,大約是17毫秒(1000ms的60分之一,60HZ)左右執(zhí)行一次(不同顯示器刷新頻率不同,75HZ,120HZ等刷新的間隔更短)。
rAF主要是做動(dòng)畫的,好處是不卡頓,動(dòng)畫也可以用setTimeout函數(shù)模擬,但是會(huì)卡頓。
為什么定時(shí)器會(huì)卡,而requestAnimationFrame不會(huì)卡
- 定時(shí)器的回調(diào)函數(shù),會(huì)受到j(luò)s的事件隊(duì)列宏任務(wù)、微任務(wù)影響,可能設(shè)定的是17毫秒執(zhí)行一次,但是實(shí)際上這次是17毫秒、下次21毫秒、再下次13毫秒執(zhí)行,所以并不是嚴(yán)格的卡住了這個(gè)60HZ的時(shí)間,會(huì)給人卡頓的感覺
為何requestAnimationFrame不會(huì)卡
- rAF能夠做到,精準(zhǔn)嚴(yán)格的卡住顯示器刷新的時(shí)間,比如普通顯示器60HZ它會(huì)自動(dòng)對(duì)應(yīng)17ms執(zhí)行一次,比如高級(jí)顯示器120HZ,它會(huì)自動(dòng)對(duì)應(yīng)9ms執(zhí)行一次。
rAF只會(huì)執(zhí)行一次,想要多次執(zhí)行,需要遞歸調(diào)用。
- rAF也有返回值,返回值是一個(gè)整數(shù),主要是定時(shí)器的身份證標(biāo)識(shí),可以使用 window.cancelAnimationFrame(返回值)來取消回調(diào)函數(shù)執(zhí)行,相當(dāng)于定時(shí)器中的clearTimeout()。
應(yīng)用-跳轉(zhuǎn)頂部動(dòng)畫
<div class="test"></div>
<button id="btn-jump">跳轉(zhuǎn)頂部</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) //跳轉(zhuǎn)y坐標(biāo)根據(jù)需求效果更改
}
}
jumpBtn.addEventListener("click",jumpFn)
</script>
應(yīng)用-進(jìn)度條
<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">進(jìn)度: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 = '進(jìn)度:' + ((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>