首頁>技術>

背景

專案中需要做一個倒計時的功能,可以根據選擇的日期,算出距離今天的時間差。倒計時有多種模板,大致分為年月日、年月日時分秒以及單獨的日。一開始也是在網上大致找了幾種方法,但要麼和專案要求不匹配,要麼計算結果不準確,就自己寫一個吧,本文記錄分享一下。

實現計算條件

年和月的差值計算是比較日期。舉個例子:比如從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寫得比較麻煩,暫時沒有特別好的思路最佳化。如果大家有發現錯誤或者更好的思路,歡迎指正。

7
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 「簡潔程式碼」20個常用的JavaScript簡寫技巧