easy date picker

简单日期选择器 - html, js & css

一直用着现成的日期选择器?

到底这东西是怎么出来的?

动手写一个!放下所有的现成!

简单的日期选择器,只用简单的web技术

语言版本:

发布日期:2015-03-06

更新日期:2015-03-06

作者:lngost

URL

1. 开始前的准备


* 简单的web技术其实并不简单,只是前人已经做好了关键部分,所以有效利用吧!

* Javascript Date 对象 是实现日期选择器的关键

方法 描述
Date() 返回当日的日期和时间
getFullYear() 获取四位数年份,例如2015
getMonth() 获取月份(0~11)
getDate() 获取某一天(1~31)
getDay() 获取星期数(0~6,0代表星期天)

(完整表格参见 W3CSchool CN

* 兼容性问题:

  (1) js方面全兼容,因为对于鼠标事件的响应,采用了html标签里的onclick属性,并未采用addEventListener;

  (2) css方面,只有2处需注意:box-shadow 支持IE9+;border-spacing 在定义了 !DOCTYPE 后支持 IE8+;

2. 成品演示


3. 开始吧!


(a) 写出对应的html

// html (final version) - by lngost

<div id="Calendar">

    <div id="Calendar-head">
        <table>
            <tr>
                <td id="Calendar-year"></td>
                <td id="Calendar-month"></td>
            </tr>
        </table>
    </div>

    <div id="Calendar-body">
        <table id="Calendar-table"></table>
    </div>

    <div id="Calendar-tail">
        <div id="tip1"></div>
        <div id="tip2" onclick="resetToToday();">Today</div>
    </div>

</div>

<div id="input-holder">
    <input type="text" name="datePicker" id="Calendar-date-input" size="25" maxlength="10" value="YYYY/MM/DD" readonly/>
</div>
calendar frame1
calendar frame2

* 除了下方的"Today"部分,其余均使用js生成,主要是因为具体日期是需要根据用户选择而动态生成的。


(b) js部分逐步解析

   - step:1

// javascript - by lngost
/*
Step:1
函数 Calendar() 是核心部分,主要包含了:
(1)当前日期的获取:myDate = new Date();
(2)年份与月份的全局变量:yearOnShow & monthOnShow
(3)一些id选择器,例如 calendarYear,
    通过使用 innerHTML 来改变显示的内容
(4)用来显示年、月、日的函数:
    displayYear();
    displayMonth();
    displayCalendarTable(yearOnShow, monthOnShow - 1);

注:将显示年、月、日的代码分别封装入3个函数的目的,
   是为了当用户改变年份和月份时,该部分代码可以通过函数直接调用,
   提高代码复用率。
*/

function Calendar() {
    /* init */
    thead = "<tr>\
                <th>Mon</th>\
                <th>Tue</th>\
                <th>Wed</th>\
                <th>Thu</th>\
                <th>Fri</th>\
                <th>Sat</th>\
                <th>Sun</th>\
            </tr>";

    myDate = new Date(); // get current date
    yearOnShow = myDate.getFullYear(); // year displayed on calendar
    monthOnShow = myDate.getMonth() + 1; // month displayed on calendar

    /* id selector */
    calendarYear = document.getElementById("Calendar-year");
    calendarMonth = document.getElementById("Calendar-month");
    calendarTable = document.getElementById("Calendar-table");
    calendarDateInput = document.getElementById("Calendar-date-input");

    /* display current Year and Month */
    displayYear();
    displayMonth();

    /* display calendar table */
    displayCalendarTable(yearOnShow, monthOnShow - 1);

} // end of Calendar()

   - step:2

// javascript - by lngost
/*
Step:2
分别写出显示年、月、日的函数:
(1)displayYear();
显示年份的同时,加上左右2个箭头用来调整年份;
并添加鼠标点击事件:onclick='preYear();' 和 onclick='nextYear();'

(2)displayMonth();
基本同上,显示月份的同时,加上箭头用来调整月份;
不满2位数的月份前,加"0"补足。

(3)displayCalendarTable(fullYear, month);
稍显复杂的部分,若了解原理,代码就很容易了;
原理如下:
* 首先考虑日历可能产生的变化情况
(规定第一行至少有一天是属于本月的)
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
或者是
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
又或者是
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
又或者是
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
以上四种,差不多是所有的极端情况了,可以看出,最少占用4行,最多占用6行;
其余的所有情况,都会介于4~6行之间。
因此,这里我们选取固定的6行,多出来的日期格子,我们可以让其显示相邻月份的日期。
(这么做的好处,就是写一个for的6次循环就可以了)

* 接着,计算出该月的1号所对应的是星期几,由于我们规定1号肯定是在第一行的,
所以开头第一行第一列的对应的日期,也就不难出来了。
注:比如设定了一个临时Date实例,var temp = new Date(2015, 3, 1),也就是2015年4月1日;
   当运行了 temp.setDate(temp.getDate() - 1) 之后,temp里的日期会自动变为2015年3月31日,十分智能。

* 最后,需注意星期数排布的不同所带来的影响
Sun Mon Tue Wed Thu Fri Sat
和
Mon Tue Wed Thu Fri Sat Sun
在编程时也是需要注意的,因为getDay()里,0代表Sun
*/

function displayYear() {
    calendarYear.innerHTML = "<span id='Calendar-year-pre' onclick='preYear();'><</span> "
                             + yearOnShow
                             + " <span id='Calendar-year-next' onclick='nextYear();'>></span>";
}

function displayMonth() {
    var temp = "<span id='Calendar-month-pre' onclick='preMonth();'><</span> ";
    if (monthOnShow < 10) {
        temp += "0" + monthOnShow;
    } else {
        temp += monthOnShow;
    }
    temp += " <span id='Calendar-month-next' onclick='nextMonth();'>></span>";
    calendarMonth.innerHTML = temp;
}

function displayCalendarTable(fullYear, month) {
    /* calculate the date of the first day on calendar table */
    var temp = new Date(fullYear, month, 1);
    var dayOnFirst = temp.getDay();
    if (dayOnFirst === 0) {
        dayOnFirst = 7;
    }
    temp.setDate(temp.getDate() - dayOnFirst + 1);

    /* count date */
    tbody = "";
    for (i = 0; i < 6; i++) {
        tbody += "<tr>";
        for (j = 1; j < 8; j++) {
            if (temp.getFullYear() === myDate.getFullYear()
                && temp.getMonth() === myDate.getMonth()
                && temp.getDate() === myDate.getDate()
                && yearOnShow === myDate.getFullYear()
                && monthOnShow - 1 === myDate.getMonth()) {
                tbody += "<td class='today' onclick='chooseDate(" + temp.getDate() + ");'>" + temp.getDate() + "</td>";
            } else if (temp.getMonth() === month) {
                tbody += "<td class='thisMonth' onclick='chooseDate(" + temp.getDate() + ");'>" + temp.getDate() + "</td>";
            } else {
                tbody += "<td class='otherMonth'>" + temp.getDate() + "</td>";
            }
            temp.setDate(temp.getDate() + 1);
        }
        tbody += "</tr>";
    }

    /* display calendar table */
    calendarTable.innerHTML = thead + tbody;
}

   - step:3

// javascript - by lngost
/*
Step:3
完善一些鼠标点击事件的函数:
preYear();前一年
nextYear();后一年
preMonth();前一个月
nextMonth();后一个月
resetToToday();返回到今天
chooseDate(date);在 <input> 里显示选中的日期
*/

function preYear() {
    yearOnShow--;
    displayYear();
    displayCalendarTable(yearOnShow, monthOnShow - 1);
}

function nextYear() {
    yearOnShow++;
    displayYear();
    displayCalendarTable(yearOnShow, monthOnShow - 1);
}

function preMonth() {
    monthOnShow--;
    if (monthOnShow < 1) {
        yearOnShow--;
        monthOnShow = 12;
        displayYear();
    }

    displayMonth();
    displayCalendarTable(yearOnShow, monthOnShow - 1);
}

function nextMonth() {
    monthOnShow++;
    if (monthOnShow > 12) {
        yearOnShow++;
        monthOnShow = 1;
        displayYear();
    }

    displayMonth();
    displayCalendarTable(yearOnShow, monthOnShow - 1);
}

function resetToToday() {
    yearOnShow = myDate.getFullYear();
    monthOnShow = myDate.getMonth() + 1;

    displayYear();
    displayMonth();
    displayCalendarTable(yearOnShow, monthOnShow - 1);
}

function chooseDate(date) {
    var dd;
    if (date < 10) {
        dd = "0" + date;
    } else {
        dd = date;
    }

    var mm;
    if (monthOnShow < 10) {
        mm = "0" + monthOnShow;
    } else {
        mm = monthOnShow;
    }
    calendarDateInput.value = yearOnShow + "/" + mm + "/" + dd;
}

   - step:4

// javascript - by lngost
/*
Step:4
别忘了加上 window.onload
*/

window.onload = function() {
    Calendar();
};

(c) css部分

* 这部分讲解起来就麻烦了,毕竟也不是一两个div就解决的东西。。。

* 以下是我的源代码

// css - by lngost

html, body {
    margin: 0;
    padding: 0;
}

#Calendar {
    width: 320px;
    box-shadow: 5px 8px 8px #D0D0D0;
    background: #F0F0F0;
    border-style: solid;
    border-width: 1px;
    border-color: #F0F0F0;
}

#Calendar-head table {
    width: 100%;
    text-align: center;
    font-size: 20px;
    margin: 15px auto 5px;
}

#Calendar-year-pre:hover, 
#Calendar-year-next:hover, 
#Calendar-month-pre:hover, 
#Calendar-month-next:hover {
    cursor: pointer;
}

#Calendar-table {
    width: 100%;
    table-layout: fixed;
    padding: 0 10px 5px;
    border-spacing: 5px;
}

#Calendar-table th {
    text-align: right;
    height: 20px;
}

#Calendar-table td {
    text-align: right;
    height: 30px;
    padding-right: 6px;
}

.today {
    color: #FFFFFF;
    background: #FF6633;
}

.today:hover {
    cursor: pointer;
}

.thisMonth {
    color: #000000;
    background: #33FF33;
}

.thisMonth:hover {
    cursor: pointer;
    background: #FFFF00;
}

.otherMonth {
    color: #C8C8C8;
    background: #FFFFFF;
}

#Calendar-tail {
    width: 100%;
    height: 50px;
}

#tip1 {
    background: #FF6633;
    width: 30px;
    height: 30px;
    margin-left: 20px;
    float: left;
}

#tip2 {
    width: 50px;
    line-height: 30px;
    float: left;
    margin-left: 8px;
}

#tip2:hover {
    cursor: pointer;
}

#input-holder {
    margin-top: 20px;
}

#input-holder input {
    font-size: 24px;
}

(The End)