背景
專案中需要做一個倒計時的功能,可以根據選擇的日期,算出距離今天的時間差。倒計時有多種模板,大致分為年月日、年月日時分秒以及單獨的日。一開始也是在網上大致找了幾種方法,但要麼和專案要求不匹配,要麼計算結果不準確,就自己寫一個吧,本文記錄分享一下。
實現計算條件年和月的差值計算是比較日期。舉個例子:比如從2月1號0時0分0秒到3月1號0時0分0秒計為相差1個月,不管當年是閏年還是非閏年,即不管2月實際有多少天。不滿1個月(計算時分秒)算0個月。年份同理。
兩種方法引用moment.js庫實現moment.js是時間處理常用的js庫,這裡使用了它的diff和subtract方法,大大簡化了工作量。透過和原生方法對比就可看出。
/** * 基於moment.js 實現的倒計時計算 * @param endTime {String,Date} - 倒計時結束時間 * @param maxUnit {String} - [maxUnit = "year"] 最大單位 * @param startTime {String,Date} - 倒計時開始時間,預設為當前時刻 * @return {Object} - 計算完成後返回的年月日時分秒數值 */ function countDownTime(endTime, maxUnit = "year", startTime) { let aUnitArr = ["year", "month", "day", "hour", "minute", "second"] let iMaxIndex = aUnitArr.indexOf(maxUnit); let end = moment(endTime); let start = moment(startTime); let result = {} if (start - end > 0) { throw new Error("開始時間不能晚於結束時間") } //過濾掉大於最大單位的單位 aUnitArr = aUnitArr.filter((item, index) => index >= iMaxIndex) result[maxUnit] = end.diff(start, maxUnit); if (aUnitArr.length > 1) { aUnitArr.reduce((previous, current) => { // 結束時間不斷減去高位單位時間 end = end.subtract(result[previous], previous); result[current] = end.diff(start, current); return current }); } return result };
原生js實現 function countDownTime2(endTime, maxUnit = "year", startTime) { let end = new Date(endTime); let start = startTime ? new Date(startTime) : new Date(); if (start - end > 0) { throw new Error("開始時間不能晚於結束時間") } let aUnitArr = [ { value: "second", interval: 60, secNum: 1 //該單位有多少秒,計算該單位最大差值用到 }, { value: "minute", interval: 60, secNum: 60 }, { value: "hour", interval: 24, secNum: 60 * 60 }, { value: "day", secNum: 60 * 60 * 24 }, { value: "month", interval: 12 }, { value: "year", }, ] let endList = getTimeList(end); let startList = getTimeList(start); const iMaxIndex = aUnitArr.findIndex(item => maxUnit === item.value); // 當最大單位為日時分秒時過濾。月份最大單位需根據年份反算所以不能過濾掉年份 if (iMaxIndex > -1 && iMaxIndex < 4) { aUnitArr = aUnitArr.filter((item, index) => iMaxIndex > -1 && index <= iMaxIndex); } let result = {}; aUnitArr.forEach((item, index) => { if (index === iMaxIndex && iMaxIndex < 4) { result[item.value] = Math.floor((end - start) / item.secNum / 1000); return } if (endList[index] - startList[index] >= 0) { result[item.value] = endList[index] - startList[index]; } else { endList[index + 1]--; result[item.value] = item.value === "day" ? countDiffDays(start, startList[index], endList[index]) : endList[index] + item.interval - startList[index]; } }) // 最大單位是月份時特殊處理 if (maxUnit === "month") { result.month += result.year * 12 delete result.year } return result; } function getTimeList(t) { return [t.getSeconds(), t.getMinutes(), t.getHours(), t.getDate(), t.getMonth() + 1, t.getFullYear()]; } // 計算日期差值。開始時間本月剩餘天數+結束時間當月日期數 function countDiffDays(time, startDay, endDay) { let curDate = new Date(time); let curMonth = curDate.getMonth(); /* 這裡將時間設定為下個月之前,需要把日期設定小一點,否則極端情況,如果當天日期大於下一個月的總天數,月份會設定為下下個月 */ curDate.setDate(1) curDate.setMonth(curMonth + 1); curDate.setDate(0);//日期設定為前一個月的最後一天 let restDays = curDate.getDate() - startDay; return restDays + endDay; };
結語原生js寫得比較麻煩,暫時沒有特別好的思路最佳化。如果大家有發現錯誤或者更好的思路,歡迎指正。
最新評論