如何寫一個簡單又通用的倒計時函式?
阿新 • • 發佈:2018-11-23
關於倒計時,可能大家都遇到/寫過這樣的UI: 13:15:16。
嗯,一個最簡單的倒計時,就是這樣。
你會怎麼實現這個邏輯?
下面是我的經歷。
第一次遇到這樣的需求時,自然而然的一路平推,非常容易的就完成了。
第二次遇到類似的需求,產品對我說要改成這樣嬸兒的:1天 13:15:16。沒毛病,掄起鍵盤,一頓control c + control v
。哎呀,需求有了一點變化,還得重新加點內容。
第三次,產品說要這樣:15:16。
......
於是我們看到,前端的需求呈碎片化且變更頻繁,即便使用 react、vue 等框架幫助我們解耦 UI 層和資料層(這極大的提高了開發效率),但面對需求我們依然疲於奔命。
怎麼解決?我認為最好的方法就是分離可變部分和不變部分。
如何識別需求中的可變和不變部分,這需要我們開發者結合實際需求、過往經驗、google等進行辨別。所以,沒有最好的方法,只有現階段你自己覺得好的方法。
針對上面需求,哪些是可變的?哪些是不變的呢?
變化部分
1、表現形式,從 13:15:16 變成 1天 13:15:16 再變成 15:16
2、倒計時結束,可能會有相應的操作,比如重新整理頁面
3、等
不變部分
計算:輸入時間值,返回符合要求的倒計時字串。可以通過函式表示 string = format(fmt, timeValue)。
// formatTime.js
const RE_FORMAT = new RegExp('%([1-9]?)(.)', 'g') const ONE_SECOND = 1000; const ONE_MINUTE = ONE_SECOND * 60; const ONE_HOUR = ONE_MINUTE * 60; const ONE_DAY = ONE_HOUR * 24; /** * @param {RegExp} fmt 按照strftime的規則,但是多了個數字,比如 "%d"=>"02", "%1d" => "2",目前支援最多以天為單位的倒計時 * @param {time} diffTime 倒計時剩餘時間 單位:毫秒 * * @return {String} fmt fmt格式的字串 */ function format(fmt, diffTime) { if (diffTime === void 0 || diffTime < 0) return diffTime let day = parseInt(diffTime / ONE_DAY) diffTime -= day * ONE_DAY let h = parseInt(diffTime / ONE_HOUR) diffTime -= h * ONE_HOUR let m = parseInt(diffTime / ONE_MINUTE) diffTime -= m * ONE_MINUTE let s = parseInt(diffTime / ONE_SECOND) let res = fmt.replace(RE_FORMAT, function(_, digit, val) { switch (val) { case 'd': // 日,01-31 return zpad(digit || 2, day); case 'H': // 時,01-24 return zpad(digit || 2, h); case 'M': // 分,01-59 return zpad(digit || 2, m); case 'S': // 秒,01-59 return zpad(digit || 2, s); case '%': return '%'; default: // 未匹配到,保持原樣 return _; } }) return res } const ZEROS = '000000000'; function zpad(n, v) { return (ZEROS + v).substr(-n) } export default { format, zpad }
最後,在 Vue 中完成倒計時:
import formatTime from './formatTime' data() { return { dataTime: '00:00:00' } }, methods: { countDown(diffTime) { if (isNaN(diffTime) || diffTime === void 0) return if (diffTime < 0) return // to do something this.downTime = formatTime.format('%H:%M:%S', diffTime) clearTimeout(this.__timer) this.__timer = setTimeout(() => this.countDown(diffTime - 1000), 1000) }, }
當然,你不一定非得使用 vue。
以上