手把手帶你分解 Vue 倒計(jì)時(shí)組件
以下內(nèi)容來自公眾號逆鋒起筆,關(guān)注每日干貨及時(shí)送達(dá)
作者:bigo前端
https://juejin.cn/post/7038405108371030047
一、前言

計(jì)時(shí)器為什么要用setTimeout而不用setInterval 為什么不直接將剩余時(shí)間-1。 如何將所需要的時(shí)間返回出去(有可能我只需要分鐘和秒數(shù),那就只返回分鐘和秒數(shù),也有可能我全都要)。 不確定接口返回的是剩余時(shí)間還是截止日期,該怎么同時(shí)兼容這兩種情況。 不確定接口返回的時(shí)間是秒還是毫秒單位。

二、開始手操 前端開發(fā)博客
1. 先創(chuàng)建一個(gè)vue組件
??"_base-count-down">
??
2. 實(shí)現(xiàn)基本的倒計(jì)時(shí)組件
time傳入這個(gè)倒計(jì)時(shí)組件,由于time可能是秒為單位的,也有可能是毫秒為單位的,所以我們需要在傳入time的是有也傳入一個(gè)isMilliSecond來告訴倒計(jì)時(shí)組件這個(gè)time是毫秒還是秒為單位的。如下代碼中的props所示。
??"_base-count-down">
??
computed中的duration是將time進(jìn)行轉(zhuǎn)化的結(jié)果,不管time是毫秒還是秒,都轉(zhuǎn)化為秒 不知道你注意到了沒有:+this.time。為什么要在前面加個(gè)‘ + ’號。這點(diǎn)很值得我們學(xué)習(xí),因?yàn)榻涌诜祷氐囊淮當(dāng)?shù)字有時(shí)候是字符串的形式,有時(shí)候是數(shù)字的形式(不能過分相信后端同學(xué),必須自己做好防范)。所以通過前面加個(gè)‘ + ’號 通通轉(zhuǎn)化為數(shù)字。現(xiàn)在的duration就是轉(zhuǎn)化后的time啦!
??"_base-count-down">
??
countDown方法調(diào)用了getTime方法,getTime需要傳入duration這個(gè)參數(shù),也就是我們獲得的剩余時(shí)間。
??"_base-count-down">
????還剩{{day}}天{{hours}}:{{mins}}:{{seconds}}
??
durationFormatter是一個(gè)將duration轉(zhuǎn)化成天數(shù),小時(shí),分鐘,秒數(shù)的方法,很簡單,可以看下它的具體實(shí)現(xiàn)。durationFormatter(time)?{
??if?(!time)?return?{?ss:?0?};
??let?t?=?time;
??const?ss?=?t?%?60;
??t?=?(t?-?ss)?/?60;
??if?(t?1)?return?{?ss?};
??const?mm?=?t?%?60;
??t?=?(t?-?mm)?/?60;
??if?(t?1)?return?{?mm,?ss?};
??const?hh?=?t?%?24;
??t?=?(t?-?hh)?/?24;
??if?(t?1)?return?{?hh,?mm,?ss?};
??const?dd?=?t;
??return?{?dd,?hh,?mm,?ss?};
},

3. 為什么要用setTimeout來模擬setInterval的行為?
setTimeout(function(){···?},?n);?//?n毫秒后執(zhí)行function
setInterval(function(){···?},?n);?//?每隔n毫秒執(zhí)行一次function
再次強(qiáng)調(diào),定時(shí)器指定的時(shí)間間隔,表示的是何時(shí)將定時(shí)器的代碼添加到消息隊(duì)列,而不是何時(shí)執(zhí)行代碼。所以真正何時(shí)執(zhí)行代碼的時(shí)間是不能保證的,取決于何時(shí)被主線程的事件循環(huán)取到,并執(zhí)行。
setInterval(function,?N)??
//即:每隔N秒把function事件推到消息隊(duì)列中

使用setInterval時(shí),某些間隔會(huì)被跳過; 可能多個(gè)定時(shí)器會(huì)連續(xù)執(zhí)行;
4. 為什么要clearTimeout(this.timer)
this.timer && clearTimeout(this.timer);這一句?
this.countDown();只會(huì)執(zhí)行一次,也就是說this.getTime(this.duration);只會(huì)執(zhí)行一次,因此duration還是活動(dòng)一的時(shí)間,怎么辦呢?watch派上用場了。微信搜索readdot,關(guān)注后回復(fù) 視頻教程 獲取23種精品資料。
??"_base-count-down">
????還剩{{day}}天{{hours}}:{{mins}}:{{seconds}}
??
this.timer && clearTimeout(this.timer);這一句?countDown(),也就調(diào)用this.getTime(this.duration);,然后執(zhí)行到setTimeout,也會(huì)一秒后把回調(diào)函數(shù)放到任務(wù)隊(duì)列中。this.timer && clearTimeout(this.timer);這一句的原因了。就是要把上一個(gè)setTimeout清除掉。5. 使用 diffTime
還剩1天12:25:25,然后有人給你發(fā)微信,你馬上切換到微信,回復(fù)消息后切回瀏覽器,發(fā)現(xiàn)倒計(jì)時(shí)時(shí)間卻還是還剩1天12:25:25。你慌了:你寫的代碼出現(xiàn)bug了!
??"_base-count-down">
????還剩{{day}}天{{hours}}:{{mins}}:{{seconds}}
??
curTime賦值Date.now(),也就是當(dāng)前的時(shí)刻,也就是顯示在頁面上的那個(gè)時(shí)刻。-1改成了-diffTime。this.days?=?dd?||?0;
this.hours?=?hh?||?0;
this.mins?=?mm?||?0;
this.seconds?=?ss?||?0;
this.curTime = Date.now(); 就記錄下了此刻的時(shí)間點(diǎn)。const now = Date.now(); 記錄當(dāng)前這個(gè)setTimeout的回調(diào)函數(shù)執(zhí)行的時(shí)間點(diǎn)。const diffTime = Math.floor((now - this.curTime) / 1000); 記錄當(dāng)前這個(gè)setTimeout的回調(diào)函數(shù)執(zhí)行的時(shí)間點(diǎn)距離頁面上開始 渲染 剩余時(shí)間的 這一段時(shí)間。其實(shí)此時(shí)的diffTime就是=1。this.curTime = now; 將curTime的值變成當(dāng)前這個(gè)setTimeout的回調(diào)函數(shù)執(zhí)行的時(shí)間點(diǎn)。this.getTime(duration - diffTime); 其實(shí)就是this.getTime(duration - 1);this.days?=?dd?||?0;
this.hours?=?hh?||?0;
this.mins?=?mm?||?0;
this.seconds?=?ss?||?0;
const now = Date.now(); 記錄當(dāng)前這個(gè)setTimeout的回調(diào)函數(shù)執(zhí)行的時(shí)間點(diǎn)。const diffTime = Math.floor((now - this.curTime) / 1000);實(shí)際上,diffTime的值就是5秒。this.getTime(duration - diffTime); 其實(shí)就是this.getTime(duration - 5);6. 添加新功能:可以傳入到期時(shí)間。
??computed:?{
????duration()?{
??????if?(this.end)?{
????????let?end?=?String(this.end).length?>=?13???+this.end?:?+this.end?*?1000;
????????end?-=?Date.now();
????????return?end;
??????}
??????const?time?=?this.isMiniSecond???Math.round(+this.time?/?1000)?:?Math.round(+this.time);
??????return?time;
????}
??},
7. 添加新功能:可以選擇要顯示的內(nèi)容,例如只顯示秒,或者只顯示小時(shí)。
??"_base-count-down?no-rtl">
????"content">
??????"{
????????d:?days,?h:?hours,?m:?mins,?s:?seconds,
????????hh:?`00${hours}`.slice(-2),
????????mm:?`00${mins}`.slice(-2),
????????ss:?`00${seconds}`.slice(-2),
??????}">
????
??
"timeObj"?:time="countDown">
??"count-down">
????"icon">
????{{timeObj.d}}天{{timeObj.hh}}小時(shí){{timeObj.mm}}分鐘{{timeObj.ss}}秒
??
00${hours}.slice(-2) 這種寫法也很值得學(xué)習(xí)。以前在獲得到分鐘的時(shí)候,要手動(dòng)判斷獲得的分鐘是兩位數(shù)還是一位數(shù),如果是一位數(shù)的話就要在前面手動(dòng)補(bǔ)上0。就像下面的代碼:var?StartMinute?=?startDate.getMinutes().toString().length?>=?2???startDate.getMinutes()?:?'0'?+?startDate.getHours();
00${hours}.slice(-2) 則不用判斷,先補(bǔ)上0再說,然后再從后面往前截取兩位。

三、學(xué)習(xí)總結(jié)
明白了setInterval的缺點(diǎn)以及用setTimeout代替setInterval。
學(xué)到了
“+”,操作,不管三七二十一,將接口得到的長串?dāng)?shù)字轉(zhuǎn)化為數(shù)字保平安。利用clearTimeout來清除掉之前的計(jì)時(shí)器,以防止造成影響。
學(xué)會(huì)使用v-slot來子傳父傳值
學(xué)會(huì)一個(gè)倒計(jì)時(shí)組件,為了以后方便cv操作。把組件完整代碼貼上:
??"_base-count-down?no-rtl">
????"content">
??????"{
????????d:?days,?h:?hours,?m:?mins,?s:?seconds,
????????hh:?`00${hours}`.slice(-2),
????????mm:?`00${mins}`.slice(-2),
????????ss:?`00${seconds}`.slice(-2),
??????}">
????
??
逆鋒起筆專注于程序員圈子,你不但可以學(xué)習(xí)到java、python等主流技術(shù)干貨和N多個(gè)源碼分享,還可以第一時(shí)間獲悉最新技術(shù)動(dòng)態(tài)、內(nèi)測資格、BAT大佬的經(jīng)驗(yàn)、精品視頻教程、副業(yè)賺錢經(jīng)驗(yàn),微信搜索readdot關(guān)注!
Vue.js 開發(fā)移動(dòng)端經(jīng)驗(yàn)總結(jié)
官宣 Vue3.0 拋棄支持 IE,把精力集中在這個(gè)上面
10 個(gè) Vue 開發(fā)技巧,助力成為更好的工程師!

評論
圖片
表情
