日历选择器

    对于日期相关处理,JavaScript 提供了 Date 对象。

    而对于比较 Date 对象的构造器有一个非常有意思的地方,那就是越界了之后,Date 会帮你自动校正日期。

    1. Sun Apr 16 2017 13:25:50 GMT+0800 (中国标准时间) // 当前日期 4/16
    2. new Date(2017, 4, 1)
    3. Mon May 01 2017 00:00:00 GMT+0800 (中国标准时间) // 日期 5/1 日

    接下来我们来看一看日期的自动修正。

    1. new Date(2017, 3, 0)
    2. Fri Mar 31 2017 00:00:00 GMT+0800 (中国标准时间) // 3 月 31 日
    3. // 4 月份的第 0 日,就是 3 月份的最后一日
    4. new Date(2017, 3, 1)
    5. Sat Apr 01 2017 00:00:00 GMT+0800 (中国标准时间) // 4 月 1 日
    6. new Date(2017, 4, 0)
    7. // 5 月份的 0 日,就是 4 月份的最后一日
    8. new Date(2017, 3, 31)
    9. Mon May 01 2017 00:00:00 GMT+0800 (中国标准时间) // 5 月 1 日
    10. 4 月份只有 30 日, 当为 31 日的时候,变成了 5月份的 1

    通过这些我们就可以获取当前月份的最后一天,以及上个月最后一天。

            *{padding: 0;margin: 0;}
            .field{
                width: 300px;
                margin: 20px auto;
                font-size: 12px;
                position: relative;
            }
            .field input{
                width: 100%;
                box-sizing: border-box;
                outline: none;
            }
            .date-select{
                background: #e8e8e8;
                color: #fff;
                cursor: pointer;
                transition: all .8s;
                position: absolute;
                width: 100%;
                z-index: 2;
                display: none;
            }
    
            .date-select table{
                width: 100%;
                border-collapse: collapse;
                text-align: center;
            }
    
    
            .date-select table caption:after{
                content: '';
                display: block;
                clear: both;
            }
    
            .date-select table caption{
                background: #999;
                line-height: 20px;
            }
    
            .date-select table th{
                background: #999;
            }
    
            .date-select table tr:first-child{
                line-height: 30px;
            }
    
            .date-select table tr td{
                 border: 1px solid #f0f0f0;
            }
    
            .date-select table tr:not(:first-child){
                line-height: 25px;
            }
    
            .date-select table caption span#prev-month{
                float: left;
                padding-left: 10px;
            }
            .date-select table caption span#next-month{
                float: right;
                padding-right: 10px;
            }
    
            const prevMonthBtn = document.querySelector('#prev-month'),
                  nextMonthBtn = document.querySelector('#next-month');
    
            const dateInput = document.querySelector('#date-input');
    
            const dateSelect = document.querySelector('.date-select');
    
            dateInput.onclick = () => {
                if(dateSelect.style.display == "block" ){
                    dateSelect.style.display = "none";
                    return;
                }
                dateSelect.style.display = "block";
            }
    
    
            prevMonthBtn.onclick = () => {
                console.log("prev");
            }
    
            nextMonthBtn.onclick = () => {
                console.log("next");
            }
    

    解释都在注释里面,仔细看一下注释,然后自己运行一下,看看结果正确不正确。

    接下来我们要把一些鼠标点击的事件,必须要等到已经渲染完HTML结构之后才能绑定,所以绑定的逻辑我们需要修改一下位置。

    为了把当月的日期明显一点,我们增加一点样式

            .date-select table tr td.current-month-day{
                background: #d6d6d6;
            }
    
    function render(date){
                let code = `
                <table>
                    <caption>
                        <span id="prev-month"> < </span>
                        <small>${date.currentYear} - ${date.currentMonth}</small>
                        <span id="next-month"> > </span>
                    </caption>
                    <tbody>
                        <tr>
                            <th>一</th>
                            <th>二</th>
                            <th>三</th>
                            <th>四</th>
                            <th>五</th>
                            <th>六</th>
                            <th>日</th>
                        </tr>
                        <tr>
                `;
    
                date.dateArray.forEach((item, index) => {
                    if(index % 7 == 0) {
                        code += '</tr><tr>'
                    }
                    code += `<td class="${date.currentMonth == item.showMonth? 'current-month-day': ''}" data-index='${item.index}'>${item.showDate}</td>`
                });
    
                dateSelect.innerHTML = code;
    
               const prevMonthBtn = document.querySelector('#prev-month'),
                     nextMonthBtn = document.querySelector('#next-month');
    
                prevMonthBtn.onclick = () => {
                    let month = date.currentMonth - 1;
                    let year = date.currentYear;
                    let prevMonthDate = get42ArrayDate(year, month);
                    render(prevMonthDate); // 重新渲染数据
                }
    
                nextMonthBtn.onclick = () => {
                    let month = date.currentMonth + 1;
                    let year = date.currentYear;
                    let nextMonthDate = get42ArrayDate(year, month);
                    render(nextMonthDate); // 重新渲染数据
                }
    
                dateSelect.addEventListener('click', (e) => {
                    let targetDom = e.target;
                    console.dir(targetDom)
                    if(targetDom.tagName == 'SPAN' || targetDom.tagName != 'TD') return;
                    let selectDay = new Date(date.currentYear, date.currentMonth - 1, targetDom.dataset.index); // currentMonth是正常月份所以要减一
                    const inputValue = selectDay.getFullYear() + " - " + (selectDay.getMonth() + 1) + " - " + selectDay.getDate();
                    dateInput.value = inputValue;
                    dateSelect.style.display = "none"; // 隐藏选择框
                },false)
    
    
            }
            let date = get42ArrayDate();
            render(date);