-
日历组件图示如下:
- 结构代码如下:
<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); }