-
日歷組件圖示如下:
calendar.PNG - 結構代碼如下:
<div id="calendar">
<!-- input輸入框 -->
<!--<div class="chooseDate">-->
<!--<input type="text" placeholder="點擊選擇時間">-->
<!--<i class="iconfont icon-rili"></i>-->
<!--</div>-->
<!-- 組件主體 -->
<!--<div class="calendar clear">-->
<!-- 日歷主體左側 -->
<!--<div class="c-show">-->
<!-- 左側展示日期的部分 -->
<!--<a class="year" href="">2017</a>-->
<!--<a class="week" href="">星期一</a>-->
<!--<a class="day" href="">4月24日</a>-->
<!-- 點擊左側年份,可展示選擇年份的列表和選擇月份的按鈕 -->
<!--<a class="chooseMonth" href="">Choose Month</a>-->
<!--<div class="yearList">-->
<!--<a class="iconfont" href="">
<i class="iconfont icon-Shang"></i>
</a>-->
<!--<a href="" class="year-item">2017</a>-->
<!--<a href="" class="year-item">2017</a>-->
<!--<a href="" class="year-item">2017</a>-->
<!--<a href="" class="year-item">2017</a>-->
<!--<a href="" class="year-item">2017</a>-->
<!--<a href="" class="year-item">2017</a>-->
<!--<a href="" class="year-item">2017</a>-->
<!--<a href="" class="year-item">2017</a>-->
<!--<a href="" class="year-item">2017</a>-->
<!--<a class="iconfont" href="">
<i class="iconfont icon-xia"></i>
</a>-->
<!--</div>-->
<!-- 點擊選擇月份,可展示月份列表和選擇年份按鈕 -->
<!--<a class="chooseYear" href="">Choose Year</a>-->
<!--<div class="monthList">-->
<!--<a href="" class="month-item">January</a>-->
<!--<a href="" class="month-item">Feberraut</a>-->
<!--<a href="" class="month-item">Jan</a>-->
<!--<a href="" class="month-item">Jan</a>-->
<!--<a href="" class="month-item">Jan</a>-->
<!--<a href="" class="month-item">Jan</a>-->
<!--<a href="" class="month-item">Jan</a>-->
<!--<a href="" class="month-item">Jan</a>-->
<!--<a href="" class="month-item">Jan</a>-->
<!--<a href="" class="month-item">Jan</a>-->
<!--<a href="" class="month-item">Jan</a>-->
<!--<a href="" class="month-item">Jan</a>-->
<!--</div>-->
<!--</div>-->
<!-- 日歷主體右側 -->
<!--<div class="c-box">-->
<!-- 日歷主體右側年月title -->
<!--<div class="c-year clear">-->
<!--<i class="iconfont icon-zuo"></i>-->
<!--<a class="years" href="">2017/4</a>-->
<!--<i class="iconfont icon-gengduo"></i>-->
<!--</div>-->
<!-- 日歷主體右側,展示一整月的日期 -->
<!--<table class="date-box">-->
<!--<thead>-->
<!--<tr>-->
<!--<th>一</th>-->
<!--<th>二</th>-->
<!--<th>三</th>-->
<!--<th>四</th>-->
<!--<th>五</th>-->
<!--<th>六</th>-->
<!--<th>日</th>-->
<!--</tr>-->
<!--</thead>-->
<!--<tbody>-->
<!--<tr>-->
<!--<td><a class="active">13</a></td>-->
<!--<td><a>23</a></td>-->
<!--<td><a>3</a></td>-->
<!--<td>4</td>-->
<!--<td>5</td>-->
<!--<td>6</td>-->
<!--<td>7</td>-->
<!--</tr>-->
<!--<tr>-->
<!--<td>1</td>-->
<!--<td>2</td>-->
<!--<td>3</td>-->
<!--<td>4</td>-->
<!--<td>5</td>-->
<!--<td>6</td>-->
<!--<td>7</td>-->
<!--</tr>-->
<!--<tr>-->
<!--<td>1</td>-->
<!--<td>2</td>-->
<!--<td>3</td>-->
<!--<td>4</td>-->
<!--<td>5</td>-->
<!--<td>6</td>-->
<!--<td>7</td>-->
<!--</tr>-->
<!--<tr>-->
<!--<td>1</td>-->
<!--<td>2</td>-->
<!--<td>3</td>-->
<!--<td>4</td>-->
<!--<td>5</td>-->
<!--<td>6</td>-->
<!--<td>7</td>-->
<!--</tr>-->
<!--<tr>-->
<!--<td>1</td>-->
<!--<td>2</td>-->
<!--<td>3</td>-->
<!--<td>4</td>-->
<!--<td>5</td>-->
<!--<td>6</td>-->
<!--<td>7</td>-->
<!--</tr>-->
<!--</tbody>-->
<!--</table>-->
<!-- 日歷主體右側底部按鈕 -->
<!--<div class="c-button">-->
<!--<a class="go-determine" href="">確定</a>-->
<!--<a class="go-today" href="">今天</a>-->
<!--</div>-->
<!--</div>-->
<!--</div>-->
</div>
- 開發過程如下:
1.通過class
定義一個Calendar
類,綁定相應屬性
2.因為操作class Calendar { //初始化 constructor(node){ this.calendarMain = node; //傳遞實例 this.calendarFound = false; //日歷未創建 this.display = false; //日歷未顯示 this.date = new Date(); this.calendarDate = {}; }
dom
有很多重復使用的方法,因此我們先封裝一部分常用方法
3.獲取//創建節點 creatElement(tag){ return document.createElement(tag); } //選擇節點 queryElement(selector,boolean){ return boolean ? document.querySelector(selector) : document.querySelectorAll(selector); } //隱藏元素 hide(elm){ elm.style.display = 'none'; } //顯示元素 show(elm){ elm.style.display = ''; }
dom
節點,創建一個實例,并調用start方法展示input
4.所有的方法都寫在Calendar類里,綁定在類的var calendarUnit = document.getElementById('calendar'); var myCalendar = new Calendar(calendarUnit); myCalendar.start();
prototype
屬性上
5.當第一次點擊//開始繪制input start(){ var cthis = this; //cthis指向Calendar //繪制chooseDate var chooseDate = this.creatElement('div'); chooseDate.className = 'chooseDate'; var input = this.creatElement('input'); input.setAttribute('type','text'); input.setAttribute('placeholder','點擊選擇時間'); var iconRili = this.creatElement('i'); iconRili.className = 'iconfont icon-rili'; //拼接chooseDate chooseDate.appendChild(input); chooseDate.appendChild(iconRili); this.calendarMain.appendChild(chooseDate); //input綁定點擊事件 this.queryElement('.chooseDate>input',true).addEventListener('click',function(){ if( !cthis.calendarFound && !cthis.display ){ //日歷未創建未顯示 cthis.create(); //創建日歷并顯示 cthis.calendarFound = true; cthis.display = true; }else if(cthis.display){ //日歷已創建已顯示 cthis.hide( cthis.queryElement('.calendar',true) ); //隱藏日歷 cthis.display = false; //修改初始值為未顯示 }else if(!cthis.display){ //日歷已創建未顯示 cthis.show( cthis.queryElement('.calendar',true) ); //顯示日歷 cthis.display = true; //修改初始值為已顯示 } }) }
input
框之后,創建并顯示日歷主體;其他非第一次點擊,只執行隱藏和顯示日歷主體
6.獲取當月天數//創建并繪制日歷 create(){ this.calendarFound = true; //修改初始值為已創建 this.display = true; //修改初始值為已顯示 //繪制calecdar var calendar = this.creatElement('div'); calendar.className = 'calendar clear'; var calendarShow = this.creatElement('div'); calendarShow.className = 'c-show'; //日歷左邊c-show var calendarBox = this.creatElement('div'); calendarBox.className = 'c-box'; //日歷右邊c-box //拼接calendar calendar.appendChild(calendarShow); calendar.appendChild(calendarBox); this.calendarMain.appendChild(calendar); //獲取當前時間保存在this.calendarDate對象里 var weeks = ['Sun','Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat']; var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec']; this.calendarDate.year = this.date.getFullYear(); //年 this.calendarDate.month = months[this.date.getMonth()]; //月 this.calendarDate.day = this.date.getDate(); //日 this.calendarDate.week = weeks[this.date.getDay()]; //周幾 //獲取當月天數并展示主體 this.calendarDate.Alldays = this.days(this.calendarDate.year,this.calendarDate.month); var calendarDate = this.calendarDate; this.initialCalendarShow(calendarDate,calendarShow,calendarBox); this.initialCalendarBox(calendarDate,calendarBox,calendarShow); }
7.初始化主體部分的左右兩側days(year,month){ var days = 30; switch (month){ case 'Jan': case 'Mar': case 'May': case 'Jul': case 'Aug': case 'Oct': case 'Dec': days = 31; break; case 'Feb': if( year % 4 === 0 && year % 100 !== 0 ){ days = 29; }else if( year % 400 === 0 ){ days = 29; }else{ days = 28; } break; } return days; }
8.渲染年份列表//初始化calendarShow initialCalendarShow(date,calendarShow,calendarBox){ var cthis = this; //繪制calendarShow calendarShow.innerHTML = ''; var showYear = this.creatElement('a'); showYear.className = 'year'; showYear.innerHTML = date.year; var showWeek = this.creatElement('a'); showWeek.className = 'week'; showWeek.innerHTML = date.week + ','; var showDay = this.creatElement('a'); showDay.className = 'day'; showDay.innerHTML = date.month + ' ' + date.day; //拼接calendarShow calendarShow.appendChild(showYear); calendarShow.appendChild(showWeek); calendarShow.appendChild(showDay); //選年選月按鈕切換 showYear.addEventListener('click',function(){ cthis.hide(showWeek); //隱藏顯示的日期 cthis.hide(showDay); // 點擊年份之后,顯示'Choose Month'和年份列表 if( showYear.innerHTML !== 'Choose Month' ){ showYear.innerHTML = 'Choose Month'; if( cthis.queryElement('.monthList',true) ){ cthis.hide( cthis.queryElement('.monthList',true) ); } cthis.chooseYear(date,calendarShow,calendarBox); }else{ // 再次點擊時,切換為顯示'Choose Year',并顯示月份列表 showYear.innerHTML = 'Choose Year'; if( cthis.queryElement('.yearList',true) ){ cthis.hide( cthis.queryElement('.yearList',true) ); } cthis.chooseMonth(date,calendarShow,calendarBox); } }) }
9.顯示月份列表//yearList chooseYear(date,calendarShow,calendarBox){ var cthis = this; date.year = parseInt(date.year); if( !this.queryElement('.yearList',true) ){ var yearList = cthis.creatElement('div'); yearList.className = 'yearList'; // 每頁顯示9個年份item // 當前年份的上一年顯示成上剪頭 // 當前年份+9年顯示成下箭頭 // 其他年份渲染成a標簽顯示 for(var i = date.year - 1;i < date.year + 10;i++){ if( i === date.year - 1 ){ var iconfontShang = cthis.creatElement('a'); iconfontShang.className = 'iconfont'; var iconShang = cthis.creatElement('i'); iconShang.className = 'iconfont icon-shang'; yearList.appendChild(iconfontShang); iconfontShang.appendChild(iconShang); }else if( i === date.year + 9 ){ var iconfontXia = cthis.creatElement('a'); iconfontXia.className = 'iconfont'; var iconXia = cthis.creatElement('i'); iconXia.className = 'iconfont icon-xia'; yearList.appendChild(iconfontXia); iconfontXia.appendChild(iconXia); }else{ var yearItem = cthis.creatElement('a'); yearItem.className = 'year-item'; yearItem.innerHTML = i; yearList.appendChild(yearItem); yearItem.addEventListener('click',function(){ date.year = this.innerHTML; // 同時渲染右側title的年份 cthis.initialCalendarBox(date,calendarBox,calendarShow,'animate'); }) } } // 拼接年份列表 calendarShow.appendChild(yearList); //向下滾動 // 將每一個當前顯示的年份+9,就是下一個年份列表 iconfontXia.addEventListener('click',function(){ var nextYearList = cthis.queryElement('.year-item'); for(var i = 0;i < nextYearList.length;i++){ nextYearList[i].innerHTML = parseInt( nextYearList[i].innerHTML ) + 9; } }) //向上滾動 iconfontShang.addEventListener('click',function(){ var lastYearList = cthis.queryElement('.year-item'); for(var i = 0;i < lastYearList.length;i++){ lastYearList[i].innerHTML = parseInt(lastYearList[i].innerHTML) - 9; } }) }else{ this.show( this.queryElement('.yearList',true) ); } }
10.準備后日期數據后,最后渲染右側日歷主體的顯示日期的部分//monthList chooseMonth(date,calendarShow,calendarBox){ var cthis = this; if( !this.queryElement('.monthList',true) ){ var monthList = cthis.creatElement('div'); monthList.className = 'monthList'; // 將月份渲染出來 var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec']; for(var i = 0;i < months.length;i++){ var monthItem = cthis.creatElement('a'); monthItem.className = 'month-item'; monthItem.innerHTML = months[i]; monthList.appendChild(monthItem) } calendarShow.appendChild(monthList); }else{ this.show( this.queryElement('.monthList',true) ); } // 給月份列表中每個月份添加點擊事件 // 修改顯示日期的月份,渲染右側 var monthItems = this.queryElement('.month-item'); for(var i = 0;i<monthItems.length;i++){ monthItems[i].addEventListener('click',function(){ date.month = this.innerHTML; cthis.initialCalendarBox(date,calendarBox,calendarShow,'animate'); }) } }
11.繪制日歷顯示日期部分時候用了//初始化calendarBox initialCalendarBox(date,calendarBox,calendarShow,animate){ var cthis = this; //繪制calendarBox calendarBox.innerHTML = ''; var control = this.creatElement('div'); control.className = 'c-year clear'; var iconZuo = this.creatElement('i'); iconZuo.className = 'iconfont icon-zuo'; var currentYear = this.creatElement('a'); currentYear.className = 'years'; currentYear.innerHTML = date.month + ' ' + date.year; var iconGengDuo = this.creatElement('i'); iconGengDuo.className = 'iconfont icon-gengduo'; //拼接calendarBox calendarBox.appendChild(control); control.appendChild(iconZuo); control.appendChild(currentYear); control.appendChild(iconGengDuo); //顯示日歷數字部分 this.dateTable(calendarBox,date,calendarShow,animate); //繪制控制按鈕 var controlButton = this.creatElement('div'); controlButton.className = 'c-button'; var deterMine = this.creatElement('a'); deterMine.className = 'go-determine'; deterMine.innerHTML = 'OK'; var today = this.creatElement('a'); today.className = 'go-today'; today.innerHTML = 'Today'; //拼接控制按鈕 calendarBox.appendChild(controlButton); controlButton.appendChild(deterMine); controlButton.appendChild(today); //today綁定點擊事件 today.addEventListener('click',function(){ var now = new Date(); var weeks = ['Sun','Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat']; var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec']; date.year = now.getFullYear(); date.month = months[now.getMonth()]; date.day = now.getDate(); date.week = weeks[now.getDay()]; date.Alldays = cthis.days(date.year,date.month); cthis.initialCalendarBox(date,calendarBox,calendarShow,'animate'); cthis.initialCalendarShow(date,calendarShow,calendarBox); }) //ok綁定點擊事件 deterMine.addEventListener('click',function(){ cthis.hide( cthis.queryElement('.calendar',true) ); cthis.display = false; cthis.queryElement('.chooseDate>input',true).value = date.day + ' ' + date.month + ' ' + date.year; cthis.initialCalendarShow(date,calendarShow,calendarBox); }) //向左滾動 this.queryElement('.icon-zuo',true).addEventListener('click',function(){ var weeks = ['Sun','Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat']; var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec']; // 2-12月,僅月份減1再重新獲取當月天數即可 if( date.month !== 'Jan' ){ var currentIdx = months.indexOf(date.month); date.month = months[currentIdx-1]; date.Alldays = cthis.days(date.year,date.month); }else{ // 如果當前已經是1月,則年份減1 ,月份顯示為12月 date.year -= 1; date.month = months[11]; } date.day = 1; var currentDate = new Date(date.year + '/' + date.month + '/' + date.day); date.week = weeks[currentDate.getDay()]; cthis.initialCalendarBox(date,calendarBox,calendarShow); cthis.initialCalendarShow(date,calendarShow,calendarBox); }) //向右滾動 this.queryElement('.icon-gengduo',true).addEventListener('click',function(){ var weeks = ['Sun','Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat']; var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec']; // 1-11月,月份加1并獲取天數即可 if( date.month !== 'Dec' ){ var currentIdx = months.indexOf(date.month); date.month = months[currentIdx+1]; date.Alldays = cthis.days(date.year,date.month); }else{ // 12時,再下一個月就是下一年了,因此年份加1,顯示一月 date.year += 1; date.month = months[0]; } date.day = 1 var currentDate = new Date(date.year + '/' + date.month + '/' + date.day); date.week = weeks[currentDate.getDay()]; cthis.initialCalendarBox(date,calendarBox,calendarShow); cthis.initialCalendarShow(date,calendarShow,calendarBox); }) }
table
標簽//顯示日歷數字部分 dateTable(calendarBox,date,calendarShow,animate){ var cthis = this; //繪制date-box var table = this.creatElement('table'); table.className = 'date-box'; var thead = this.creatElement('thead'); var theadTr = this.creatElement('tr'); var header = ['S','M','T','W','T','F','S']; header.forEach(function(val){ var th = cthis.creatElement('th'); th.innerHTML = val; theadTr.appendChild(th); }) //拼接date-box table.appendChild(thead); thead.appendChild(theadTr); table.className == 'animate' ? '' : 'animate'; //得到每月第一天周幾 var tbody = this.creatElement('tbody'); var firstDay = new Date(date.year + '/' + date.month + '/' + 1).getDay(); //計算出一個月中的每個周日 //i表示本月table第幾天,date.Alldays+firstDay-1表示循環次數,需要加上table中空缺的前幾天 for(var i = 0;i < date.Alldays + firstDay;i++){ // 當是table的第1、7、14、21、28天,也就是table周日的位置,新建一行 if( i === 0 || i % 7 === 0 ){ var tbodyTr = this.creatElement('tr'); } // 非周日的,新建td var td = this.creatElement('td'); // 只有當i循環到等于本月第一天的時候,才開始真正的本月table渲染 if( i >= firstDay ){ var a = this.creatElement('a'); var currentDay = i - firstDay + 1; //當前是本月幾號 a.innerHTML = currentDay; // 當循環的到當前時間剛好是獲取的今天時 if( date.day === currentDay){ a.className = 'active'; } a.addEventListener('click',function(){ var weeks = ['Sun','Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat']; date.day = parseInt(this.innerHTML); var currentDate = new Date(date.year + '/' + date.month + '/' + date.day); date.week = weeks[currentDate.getDay()]; cthis.initialCalendarBox(date,calendarBox,calendarShow); cthis.initialCalendarShow(date,calendarShow,calendarBox); }) td.appendChild(a); } tbodyTr.appendChild(td) if( i === 0 || i % 7 === 0 ){ tbody.appendChild(tbodyTr); } } table.appendChild(tbody); calendarBox.appendChild(table); }