本文發佈在個人博客 如何寫一個日曆組件
許可協議: 署名-非商業性使用-禁止演繹 4.0 國際 轉載請保留原文連接及做者。
衆所周知,雖然
javascript
中關於時間的API有很多,咱們能夠經過方法單獨的獲取年、月、日、時、分、秒、毫秒...貌似不少,最近寫了一個日曆(之前寫的,但寫得很爛,最近優化一下),因此下面簡單的記錄一下如何寫一個日曆,列出了一些我在寫日曆過程當中本身封裝的一些方法
先來一張效果圖,因爲沒有UI設計,因此就本身簡單的設計了一個樣式(好歹我也是設計專業的,雖然已不作設計不少年),雖然略醜,但重要的是功能!!!javascript
一個日曆究竟是怎樣用代碼生成的?其實觀察一下現有的日曆展示形式,能夠很快的造成思路,就是:根據計算把日期號數對應到正確的星期幾上,並按照順序逐一輸出。
如下是個人思路:vue
循環對應號數和星期幾返回一個數組對象java
注意,爲了保持方便調用javascript
的方法,以及保持輸出結果符合實際,全部的方法都有以下約定:git
在計算過程當中github
在輸出的結果中數組
因此在向調用方法傳遞參數過程當中,月份以及星期幾通通都須要按照實際月份減一優化
在javascript
中沒有直接獲取月份天數的方法,可是它提供了一個getDate
方法能夠獲取日期的某一天。那咱們只須要獲取月份的最後一天(下一個月的第0天)就能夠得知這個月的天數:ui
// year是要獲取的年份,閏年不同 // month是要獲取的月份 // 返回當前月天數 function getMonthDays(year, month){ return new Date(year, month, 0).getDate(); } getMonthDays(2016,2) //29 getMonthDays(2017,2) //28
// year是要獲取的年份 // month是要獲取的月份 // 返回數字幾則是星期幾 function getWeekday(year, month, day){ return new Date(year, month-1, day).getDay(); } getWeekday(2016,10,9) //輸出4,表示2016年11月9是星期4 getWeekday(2017,10,9) //輸出5,表示2017年11月9是星期5
要計算月份包含幾個星期,須要兩個數據:月份天數和月份第一天是星期幾,就能獲得想要的結果this
// year是要獲取的年份 // month是要獲取的月份 // 返回當前月包含幾個星期 function getweeksInMonth(year, month){ var days = getMonthDays(year, month); var FirstDayWeekday = getWeekday(year, month, 1); return Math.ceil((days + FirstDayWeekday) / 7); }
有了以上方法以後,就能夠經過循環生成一個簡單的月份對象了。
在這裏須要注意,日曆的排序有兩種:spa
// year是要獲取的年份 // month是要獲取的月份 // day天,用來判斷是不是當前天 // type代表要星期幾開頭,0爲星期一開頭,1爲星期日開頭,默認爲0 // 返回當前月包含幾個星期 const WEEKTABLE = [{ cn: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'], cns: ['日', '一', '二', '三', '四', '五', '六'], en: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] },{ cn: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'], cns: ['一', '二', '三', '四', '五', '六', '日'], en: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }] getMonthDaysArray(year, month, day, type) { if (typeof day === 'undefined' && year === YEAR && month === MONTH) day = DAY; var dayArrays = []; var days = this.getMonthDays(year, month), preDays = this.getMonthDays(year, month - 1); var thisMonthFirstDayInWeek = this.getWeekday(year, month, 1), thisMonthLastDayInWeek = this.getWeekday(year, month, days); type = !type || type !== 1 ? 0 : 1; //上月在當月日曆面板中的排列 for (var i = 0; i < thisMonthFirstDayInWeek; i++) { dayArrays.push({ dayNum: (preDays - thisMonthFirstDayInWeek + i + 1), weekDay: WEEKTABLE[type].cn[i] }) } //當月日曆面板中的排列 for (var i = 1; i <= days; i++) { var weekDayFlag = (thisMonthFirstDayInWeek + i - 1) % 7 dayArrays.push({ dayNum: i, weekDay: WEEKTABLE[type].cn[weekDayFlag], selected: i === +day, isThisMonth: true }) }; //下月在當月日曆面板中的排列 for (var i = 1; i <= (6 - thisMonthLastDayInWeek); i++) { var weekDayFlag = (thisMonthFirstDayInWeek + days + i - 1) % 7 dayArrays.push({ dayNum: i, weekDay: WEEKTABLE[type].cn[weekDayFlag] }) }; return dayArrays; }
涉及到時間時,經常須要把時間格式進行轉換,爲了應對多中需求,因此本身封裝了一個
// 參數fmt必須 // date參數沒必要須,容許字符串和時間對象,不傳或者傳沒法轉換成合法時間對象的字符串則默認當前時間, // 年(YYYY/yyyy)固定四個佔位符 // 月(M)、日(d)、小時(h)、分(m)、秒(s)能夠用 1-2個佔位符,嚴格區分大小寫, // 毫秒(ms/mss)最多三個佔位符,分別對應56,056這種類型 // 例子: // (Format("yyyy-MM-dd hh:mm:ss:ms") ==> 2006-07-02 08:09:04:23 // (Format("yyyy-MM-dd hh:mm:ss:mss") ==> 2006-07-02 08:09:04:023 // (Format("yyyy-M-d h:m:s:ms") ==> 2006-7-2 8:9:4.180 function formate(fmt, date){ date = new Date(date).toString() === 'Invalid Date' ? new Date() : new Date(date); var _rules = [{ rule: '[yY]{4}', value: _date.getFullYear() }, { rule: 'M+', value: _date.getMonth() + 1 }, { rule: '[dD]+', value: _date.getDate() }, { rule: 'h+', value: _date.getHours() }, { rule: 'm+', value: _date.getMinutes() }, { rule: 's+', value: _date.getSeconds() }, { rule: 'ms{1,2}', value: _date.getMilliseconds() }]; _rules.forEach(function (_r){ const rule = _r.rule, val = _r.value; fmt = fmt.replace(new RegExp(rule), function ($1) { const rLen = val.toString().length, fLen = $1.length; return (fLen !== 2 || rLen >= fLen) ? val : ['00', val].join().substr(rLen); }); }); return fmt; } //調用: var time1 = formate("YYYY/MM/DD hh:mm:ss", new Date()); //2017/11/2 11:09:20 var time2 = formate("YYYY-MM-DD", time1); //2017-11-2 var time3 = formate("MM-DD-YYYY", time2); //11-2-2017
附上這些方法的源碼datepicker
基於vue實現的一個日曆:
固然這只是最簡單的日曆輸出,思路也是超級簡單(感受有點Low),若是有大神願意分享它的經驗歡迎,來郵~