日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
基于RequestAnimationFrame實現(xiàn)高精度毫秒級正向計時器

背景

最近做了一個周末嘉年華的活動【免費領(lǐng)取「王者榮耀千元賬號」】,效果圖如下。玩法也很簡單:點擊開始,計時器開始計時,點擊停止,點擊開始按鈕后會變成停止,當(dāng)計時結(jié)束時,秒表顯示時間為 10:00 時,即可獲取 「價值千元的王者榮耀賬號」!

網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、微信平臺小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了呼倫貝爾免費建站歡迎大家使用!

編組

點我體驗 !?。?/p>

若遇到活動未開始或者活動結(jié)束,可以前往轉(zhuǎn)轉(zhuǎn)app搜索【游戲】即可參與更多活動,各種福利拿到手軟!

需求分析

從圖上可以看出來,核心就是一個正向計時器。通過js實現(xiàn)一個普通的正向計時器很簡單,大多數(shù)想到都是使用setInterval來實現(xiàn)。那么還有沒有其他的實現(xiàn)方式呢?又怎么去實現(xiàn)一個高精度的毫秒級正向計時器呢?

最近看了vant4的倒計時組件的源碼,發(fā)現(xiàn)其并沒有使用setInterval, 而是封裝了requestAnimationFrame 和利用 Date.now()來處理毫秒級渲染和倒計時實現(xiàn)。那么能不能通過requestAnimationFrame來實現(xiàn)一個正向計時器呢?

先看看效果圖,接下來將會一步步去實現(xiàn):

體驗地址: https://suyxh.github.io/timer-demo/

setInterval版

首先呢,來看看使用setInterval是如何實現(xiàn)的。在網(wǎng)上看了很多文章,大多都是使用的 setInterval 去實現(xiàn),大致效果如下:

setinterval

從效果圖上我們可以發(fā)現(xiàn),最后一位始終為0,甚至還是有些小bug,很明顯不是我們想要的。具體代碼如下:








Document
















requestAnimationFrame版

上文中提到vant的CutDown組件,主要就是利用 Date.now() 會自己走的原理,結(jié)合 requestAnimationFrame 去做時間計算;那么正向計時器則是利用了 requestAnimationFrame 回調(diào)函數(shù)的參數(shù)去做時間計算,從而實現(xiàn)毫秒級的計時器。

「window.requestAnimationFrame()」 告訴瀏覽器——你希望執(zhí)行一個動畫,并且要求瀏覽器在下次重繪之前調(diào)用指定的回調(diào)函數(shù)更新動畫。該方法需要傳入一個回調(diào)函數(shù)作為參數(shù),該回調(diào)函數(shù)會在瀏覽器下一次重繪之前執(zhí)行,當(dāng)你準(zhǔn)備更新動畫時你應(yīng)該調(diào)用此方法。這將使瀏覽器在下一次重繪之前調(diào)用你傳入給該方法的動畫函數(shù) (即你的回調(diào)函數(shù))。

「注意:」 若你想在瀏覽器下次重繪之前繼續(xù)更新下一幀動畫,那么回調(diào)函數(shù)自身必須再次調(diào)用 window.requestAnimationFrame()

MDN requestAnimationFrame

「參數(shù)」

  • callback?下一次重繪之前更新動畫幀所調(diào)用的函數(shù) (即上面所說的回調(diào)函數(shù))。該回調(diào)函數(shù)會被傳入DOMHighResTimeStamp參數(shù),該參數(shù)與performance.now()的返回值相同,它表示requestAnimationFrame() 開始去執(zhí)行回調(diào)函數(shù)的時刻。

「返回值」

一個 long 整數(shù),請求 ID,是回調(diào)列表中唯一的標(biāo)識。是個非零值,沒別的意義。你可以傳這個值給 window.cancelAnimationFrame() 以取消回調(diào)函數(shù)。

測試版

通過 requestAnimationFrame API可以知道,回調(diào)函數(shù)中的參數(shù)就是一個 DOMHighResTimeStamp參數(shù),該參數(shù)與performance.now()的返回值相同,它表示requestAnimationFrame() 開始去執(zhí)行回調(diào)函數(shù)的時刻。

那我們直接使用該值不就可以了嗎?試試看:








Document



hello world

這里顯示倒計時狀態(tài)









效果如下:

測試版

雖然比較簡陋,但是并沒有出現(xiàn) setInterval版 的bug,接下來在一步步優(yōu)化。

簡易版

我們加上格式化時間的函數(shù) parseTime() 和 parseFormat(), 代碼如下:








Document



hello world

這里顯示倒計時狀態(tài)









效果如下:

簡易版

又看到了我們熟悉的時間格式啦, 格式化的方法也是來源于vant的CutDown組件中的格式化代碼!

格式化雖然是完成了,但是怎么去停止呢?能不能支持暫停、繼續(xù)、重置呢?

接下來繼續(xù)完善。

進(jìn)階版

我們直接通過 window.cancelAnimationFrame() 去取消回調(diào)函數(shù)即可!在 useCountUp函數(shù)中添加一下 pause 即可!

const pause = () {
if (rafId) {
window.cancelAnimationFrame(rafId)
}
}

效果如下:

進(jìn)階版

不少的小伙伴已經(jīng)發(fā)現(xiàn),停止雖然是沒問題了,當(dāng)再次點擊開始的時候,時間怎么不對了?有瑕疵!

因為我們少算補(bǔ)時時間,做如下修改,添加startTime 、 stopTime 和  goOn 方法:

const useCountUp = () {
let rafId;
let startTime;
let stopTime;


const step = (timestamp) => {
console.log('timestamp', timestamp)
render(timestamp - startTime)
rafId = window.requestAnimationFrame(step)
}

const start = () {
startTime = performance.now()
rafId = window.requestAnimationFrame(step)
}

const pause = () {
stopTime = performance.now()
if (rafId) {
window.cancelAnimationFrame(rafId)
}
}

const goOn = () {
startTime += performance.now() - stopTime
rafId = window.requestAnimationFrame(step)
}

return {
start,
pause,
goOn
}
}

這里基本上已經(jīng)完成了暫停和繼續(xù)的功能了,但是仍是有些bug的,可以多次點擊繼續(xù)試試 。

完整版

接下來,我們來修復(fù)上述的bug,方法:添加一個變量來表示當(dāng)前計時器的狀態(tài)。

在增加幾個新功能:

  • 添加 重置 方法: 其實我們只需要調(diào)用一下暫停,在清理一下時間即可
  • 支持 配置:比如 正香計時的時間, 計時結(jié)束的函數(shù)

核心代碼如下,其他部分代碼不變:

const useCountUp = (options) => {
let rafId, startTime, stopTime, curentTime, counting = false

const step = (timestamp) => {
curentTime = timestamp - startTime
render(curentTime)
options.onChange?.(curentTime);

if (options.time) {
if (Math.floor(curentTime) < options.time) {
rafId = window.requestAnimationFrame(step)
} else {
pause()
options.onFinish?.()
}
} else {
rafId = window.requestAnimationFrame(step)
}

}

const start = () {
// 計時中 或者 已經(jīng)開始過計時想要重新開始計時,應(yīng)該先點擊一下 重置 再開始計時
if (counting || curentTime) {
return
}
counting = true
startTime = performance.now()
rafId = window.requestAnimationFrame(step)
}

const pause = () {
// 已經(jīng)暫停后,屏蔽掉點擊
if (!counting) {
return
}
counting = false
stopTime = performance.now()
if (rafId) {
window.cancelAnimationFrame(rafId)
}
}

const goOn = () {
// 已經(jīng)在計時中,屏蔽掉點擊
if (counting) {
return
}
counting = true
startTime += performance.now() - stopTime
rafId = window.requestAnimationFrame(step)
}

const reset = () {
pause()
curentTime = 0
startTime = 0
stopTime = 0
render(0)
}

return {
start,
pause,
goOn,
reset
}
}

const { start, pause, goOn, reset } = useCountUp({
time: 3 * 1000,
onChange: current console.log('change', current),
onFinish: () console.log('finish'),
});

document.querySelector('.start').addEventListener('click', () => {
start()
})

document.querySelector('.pause').addEventListener('click', () => {
pause()
})

document.querySelector('.goOn').addEventListener('click', () => {
goOn()
})

document.querySelector('.reset').addEventListener('click', () => {
reset()
})

到此基本上就是實現(xiàn)了一個毫秒級的正向計時器!

vue版

只是對js的邏輯進(jìn)行了一些封裝

代碼:https://github.com/SuYxh/timer-demo

預(yù)覽:https://suyxh.github.io/timer-demo/

總結(jié)

正向毫秒級計時器主要就是利用了window.requestAnimationFrame的回調(diào)函數(shù)的參數(shù)為DOMHighResTimeStamp,且與performance.now()的返回值相同;在實現(xiàn)暫停、繼續(xù)時,需要計算一下補(bǔ)時時間。


新聞標(biāo)題:基于RequestAnimationFrame實現(xiàn)高精度毫秒級正向計時器
網(wǎng)站地址:http://www.5511xx.com/article/dhspdhj.html