1. 程式人生 > >JS日期選擇器

JS日期選擇器

指定 腳本 scrolltop 滾動條 opacity efi length eof data

<input type="date">在三個瀏覽器中彈出的日期框都不一樣(下圖依次谷歌,EDGE,火狐)

技術分享圖片技術分享圖片技術分享圖片

谷歌的比較質普,EDGE的像半成品,火狐的比較好看.

模仿火狐做個練習.

技術分享圖片技術分享圖片

思路與體會:

  1.將日期框分三行,第一行是年,月,今天. 第二行是周,像是一個表格標題頭.第三行是六行七列的日(天)

  2.建日期類.初始化年月日,一般是由INPUT框中傳來,沒有默認為當天的.類中保留INPTU的引用.其它需要生成年,月,日數據的方法和生成DOM的方法.最終由一個方法生成日期框全部的DOM.

  3.六行七列的天數,起止點是由給定的年月計算,在這年月的1號往前推到最近的周日,這年月的最後一天後推到最近的周六.得出.

  4.類方法放到INPUT的點擊事件上彈出日期框,同時獲得焦點.失去焦點時日期框消失.

  5.日期計算並不太復雜,主要樣式和腳本生成DOM費了工夫.出了一些BUG.主要是日期計算時,月份是0-11表示1-12月.

日期框:

  樣式模仿火狐版本的日期框

  年份選項區範圍1900-2100 手工輸入(INPUT框)年份0-9999可識別

  年份和月份不能在框上輸入,只能選擇.

  不屬於選定年月中的日,選中的日,今天.顏色上有區分

  年份月份分別前進後退按鈕

代碼:

技術分享圖片
/*
日期類:將此函數作為日期框事件函數,傳入this(日期框)
需要引用:JQ,JsExtFun.js
 
*/ function mydate(input) { // 初始化已選年月日 mydate.initDate(input); // 生成DOM var datedom = mydate.createDom(); // 根據日期框的位置顯示日期DOM框 var thisleft = $(input).offset().left; var thistop = $(input).offset().top + $(input).outerHeight(); $(‘.mydatebox‘).remove(); // 顯示新的日期框
$(‘body‘).append(String.DataBind(datedom, { left: thisleft, top: thistop })); $(‘.mydatebox‘).focus(); } // 觸發日期框的INPUT的JQ對象引用 mydate.InputJQ; // 初始年 mydate.Year; // 初始月[0-11] mydate.Month; // 初始日[1-31] mydate.Day; // 初始化:已選年月,保存日期框的INPUT的JQ對象引用 mydate.initDate = function (input) { // 初始化選定年月日,如果沒有,則默認今天 var date = new Date(); if (input.value.IsDate()) { var ymd = input.value.split(‘-‘); date = new Date(parseInt(ymd[0]), parseInt(ymd[1]) - 1, parseInt(ymd[2])); } mydate.Year = date.getFullYear(); mydate.Month = date.getMonth(); mydate.Day = date.getDate(); mydate.InputJQ = $(input); } // 生成整個日期框的DOM.並返回 mydate.createDom = function () { var box = ‘<div class="mydatebox" style="left:${left}px;top:${top}px" tabindex="-1" onblur="mydate.close()">{0}{1}{2}</div>‘; var yearrow = String.Format(‘<div class="yearrow">{0}{1}{2}</div>‘ , mydate.createDom_Year() , mydate.createDom_Month() , ‘<div class="todayarea"><a class="today" onclick="mydate.todayBtn_click(this)">今天</a></div>‘); var weekrow = String.Format(‘<div class="weekrow">{0}</div>‘ , mydate.createDom_Week()); var daysrows = String.Format(‘<div class="daysrows">{0}</div>‘ , mydate.createDom_Day()); return String.Format(box, yearrow, weekrow, daysrows); } // 生成年份區DOM片段.並返回. mydate.createDom_Year = function () { var box = ‘<div class="yeararea">${prevbtn}${yearbtn}${nextbtn}</div>‘; var data = {}; data.prevbtn = ‘<a class="prevbtn" onclick="mydate.prevnextYM_click(this,1,2)">&lt;</a>‘; data.yearbtn = String.Format( ‘<b class="yearbtn" onclick="mydate.yearBtn_click(this)" val="{0}">{0}年</b>‘ , mydate.Year); data.nextbtn = ‘<a class="nextbtn" onclick="mydate.prevnextYM_click(this,1,1)">&gt;</a>‘; return box = String.DataBind(box, data); } // 年份選擇項DOM片段.selectedYear:可指定一個年份為已選定 mydate.createDom_YearSelect = function (selectedYear) { var ydoms = ‘‘; var ylist = mydate.domYear_Data(); for (var i = 0; i < ylist.length; i++) { ydoms += String.Format(‘<b class="{0}" val="{1}" onclick="mydate.yearSelected(this)">{1}</b>‘, ylist[i] == selectedYear ? "selected" : "", ylist[i]); } return String.Format(‘<div class="yearsops">{0}</div>‘, ydoms); } // 生成月份區DOM片段.並返回. mydate.createDom_Month = function () { var box = ‘<div class="montharea">${prevbtn}${monthbtn}${nextbtn}</div>‘; var data = {}; data.prevbtn = ‘<a class="prevbtn" onclick="mydate.prevnextYM_click(this,2,2)">&lt;</a>‘; data.monthbtn = String.Format(‘<b class="monthbtn" onclick="mydate.monthBtn_click(this)" val="{0}">{1}月</b>‘ ,mydate.Month, mydate.Month + 1); data.nextbtn = ‘<a class="nextbtn" onclick="mydate.prevnextYM_click(this,2,1)">&gt;</a>‘; return box = String.DataBind(box, data); } // 生成月份選擇項DOM片段 selectedMonth:可指定一個月份為已選定 mydate.createDom_MonthSelect = function (selectedMonth) { var mdoms = ‘‘; for (var i = 0; i < 12; i++) { mdoms += String.Format( ‘<b class="{0}" onclick="mydate.monthSelected(this)" val="{1}">{2}</b>‘ , selectedMonth == i ? "selected" : ‘‘,i, i + 1); } return String.Format(‘<div class="monthsops">{0}</div>‘, mdoms); } // 生成星期標題頭DOM版本.並返回 mydate.createDom_Week = function () { var weeksdom = ‘‘; var weeks = [‘日‘, ‘一‘, ‘二‘, ‘三‘, ‘四‘, ‘五‘, ‘六‘]; for (var i = 0; i < weeks.length; i++) { weeksdom += ‘<b>周‘ + weeks[i] + ‘</b>‘; } return weeksdom; } // 生成日選項DOM片段.並返回.daylist:日數據.不傳則使用選定年月計算出日 mydate.createDom_Day = function (daylist) { var data = typeof daylist == ‘undefined‘ ? mydate.domDay_Data() : daylist; var daydoms = ‘‘; var index = 0; for (var i = 0; i < 6; i++) { var weeksdays = ‘‘; for (var j = 0; j < 7; j++) { var json = data[index]; var daydom = ‘<b class="${istoday} ${isdayinmonth} ${isselected}" year="${yyyy}" month="${MM}" day="${dd}" onclick="mydate.day_click(this)">${dd}</b>‘; json.istoday = json.istoday ? ‘today‘ : ‘‘; json.isselected = json.isselected ? ‘selected‘ : ‘‘; json.isdayinmonth = json.isdayinmonth ? ‘‘ : ‘dayoutmonth‘; weeksdays += String.DataBind(daydom, json); index++; } daydoms += String.Format(‘<div class="daysrow">{0}</div>‘, weeksdays); } return daydoms; } /* 為DOM提供的數據,年份 日 */ // 根據已選年計算年份選項 mydate.domYear_Data = function () { // 年份選擇範圍固定在[1900-2100] var data = []; for (var i = 1900; i < 2101; i++) { data.push(i); } return data; /**動態年份數據舊代碼.**/ //// 年份範圍[0-9999](7個,已選年在中間) //var ymid = mydate.Year; //if (typeof yearmiddle != ‘undefined‘) //{ // ymid = parseInt(yearmiddle); //} //if (ymid < 3) // ymid = 3; //else if (ymid > 9996) // ymid = 9996; //var data = []; //for (var i = -3; i < 4; i++) //{ // data.push(ymid + i); //} ////console.log(data); //return data; /****************************************************/ } // 根據已選年月或者傳入指定年月,計算日的起始和結束 // 日(天)總共六行七列42個,含已選年月所有日, 前推至最近的周日, 後推至最近或次近的周六 mydate.domDay_Data = function (yyyy,mm) { // 指定年 var seledY = typeof yyyy == ‘undefined‘ ? mydate.Year : parseInt(yyyy); // 指定月 var seledM = typeof mm == ‘undefined‘ ? mydate.Month : parseInt(mm); // 指定年月的起止日(1~xx號) var firstdate = new Date(seledY, seledM, 1); var lastdate = new Date(seledY, seledM + 1, 0); // 根據日所在的星期0-6排列顯示,確定1日和最後日是星期幾 var week1day = firstdate.getDay(); //var weeklastday = lastdate.getDay(); // 1日往前推到最近的周日(起點),最後日推到最近的周六(終點) firstdate.setDate(firstdate.getDate() - week1day); //lastdate.setDate(lastdate.getDate() + (6 - weeklastday)); var todaystr = (new Date()).toLocaleDateString(); var daysrange = []; for (var i = 0; i < 42; i++) { var json = {}; json.yyyy = firstdate.getFullYear(); json.MM = firstdate.getMonth(); json.dd = firstdate.getDate(); // 日是否屬於指定年月中的日 json.isdayinmonth = json.MM == seledM; // 日是否為今天 json.istoday = firstdate.toLocaleDateString() == todaystr; // 日是否選定(等於文本框中已選日) json.isselected = (json.yyyy == mydate.Year && json.MM==mydate.Month && json.dd == mydate.Day); firstdate.setDate(json.dd + 1); daysrange.push(json); } return daysrange; } /* 事件方法:年月的前進後退按鈕,年月選擇按鈕,今天按鈕 */ // 點擊年按鈕 顯示年選擇框 mydate.yearBtn_click = function (thisobj) { var seledY = $(thisobj).attr(‘val‘); var yearsops = $(thisobj).parent().find(‘.yearsops‘); if (yearsops.length == 1) { yearsops.remove(); return; } $(thisobj).parent().append(mydate.createDom_YearSelect(seledY)); // 定位已選年份到滾動框的中間(視口可見範圍內) var yopsbox = $(thisobj).parent().find(‘.yearsops‘); var yseled = yopsbox.find(‘.selected‘); if (yseled.length == 0) yseled = yopsbox.find(‘[val=‘ + (new Date()).getFullYear() + ‘]‘); // 計算這個年份選項離父框的TOP值,然後滾動條滾動這個值-100(父框高(200)/2) var scrollval = yseled.position().top - 100; yopsbox.scrollTop(scrollval); } // 年選擇框 上下翻頁按鈕1=上0=下 //mydate.yearTurn_click = function (thisobj, turntype) //{ // // 上翻:以第一個年份選項為中點,下翻以最後年份為中點 // var yops = $(thisobj).parent().find(‘b‘); // var ymiddle = turntype == 1 ? yops.first() : yops.last(); // var newyops = mydate.createDom_YearSelect(ymiddle.attr(‘val‘)); // // 替換新的年份選項 // $(thisobj).parent().html($(newyops).children()); //} // 選定一個年份 mydate.yearSelected = function (thisobj) { // 日期DOM最外層JQ var datebox = $(thisobj).closest(‘.mydatebox‘); // 所選年份值 var y = $(thisobj).attr(‘val‘); datebox.find(‘.yearrow .yearbtn‘).attr(‘val‘, y).html(y + ‘年‘); // 關閉年份選擇框 $(thisobj).parent().remove(); // 刷新 日 var m = datebox.find(‘.yearrow .monthbtn‘).attr(‘val‘); mydate.resetDaysDom(y, m, datebox.find(‘.daysrows‘)); } // 點擊月按鈕 顯示月選擇框 mydate.monthBtn_click = function (thisobj) { var seledM = $(thisobj).attr(‘val‘); var monthsops = $(thisobj).parent().find(‘.monthsops‘); if (monthsops.length == 1) { monthsops.remove(); return; } $(thisobj).parent().append(mydate.createDom_MonthSelect(seledM)); } // 選定一個月份 mydate.monthSelected = function (thisobj) { // 日期DOM最外層JQ var datebox = $(thisobj).closest(‘.mydatebox‘); // 所選月份值 var m = parseInt($(thisobj).attr(‘val‘)); datebox.find(‘.yearrow .monthbtn‘).attr(‘val‘, m).html((m+1) + ‘月‘); // 關閉月份選擇框 $(thisobj).parent().remove(); // 刷新 日 var y = datebox.find(‘.yearrow .yearbtn‘).attr(‘val‘); mydate.resetDaysDom(y, m, datebox.find(‘.daysrows‘)); } // 點擊年份,月份的前進和後退按鈕 yOrm:1=年按鈕,2=月按鈕. pOrn:1=前進,2=後退 mydate.prevnextYM_click = function (thisobj,yOrm,pOrn) { // 日期DOM最外層JQ var datebox = $(thisobj).closest(‘.mydatebox‘); var ybtn = datebox.find(‘.yearrow .yearbtn‘); var mbtn = datebox.find(‘.yearrow .monthbtn‘); var y = parseInt(ybtn.attr(‘val‘)); var m = parseInt(mbtn.attr(‘val‘)); // 計算並刷新年或月按鈕值 年份前進後退值[1-9999] if (yOrm == 1) { y = pOrn == 1 ? y + 1 : y - 1; if (y < 1) y = 9999; else if (y > 9999) y = 1; } else if (yOrm == 2) { m = pOrn == 1 ? m + 1 : m - 1; if (m < 0) m = 11; else if (m > 11) m = 0; } ybtn.attr(‘val‘, y).html(y + ‘年‘); mbtn.attr(‘val‘, m).html((m + 1) + ‘月‘); // 刷新日 mydate.resetDaysDom(y, m, datebox.find(‘.daysrows‘)); } // 點擊今天按鈕 mydate.todayBtn_click = function (thisobj) { var today = new Date(); mydate.InputJQ.val(today.ToString(1)); mydate.close(); } // 點擊日(天) mydate.day_click = function (thisobj) { var date = new Date($(thisobj).attr(‘year‘), $(thisobj).attr(‘month‘) , $(thisobj).attr(‘day‘) ); mydate.InputJQ.val(date.ToString(1)); mydate.close(); } // 根據選定的年,月刷新日(用於當在日期框上操作年,月等會改變年月的動作時) // yyyy:指定年,mm:指定月 daysdom:日的父級DOM的JQ對象(.daysrows) mydate.resetDaysDom = function (yyyy,mm,daysdombox) { // 計算出指定年月的日數據 var dayslist = mydate.domDay_Data(yyyy, mm); // 生成日DOM var daysrowdom = mydate.createDom_Day(dayslist); // 替換日DOM daysdombox.html(daysrowdom); } // 關閉日期框 mydate.close = function () { mydate.InputJQ = null; mydate.Year = null; mydate.Month = null; mydate.Day = null; $(‘.mydatebox‘).remove(); }
mydate.js

樣式:

技術分享圖片
/*外框*/
.mydatebox {
    position:absolute;
    width: 308px;
    box-sizing: border-box;
    font-size: 0;
    text-align: center;
    cursor: default;
    border: 1px solid #ccc;
    padding: 5px 0 10px 0;
    box-shadow: 1px 1px 10px #eee;
    -moz-user-select: none;
    -ms-user-select: none;
    -webkit-user-select: none;
    user-select: none;
    outline:none;
}
/*第1行 含有年月及前進和今天按鈕*/
.yearrow {
    box-sizing: border-box;
    padding: 5px;
}
    /*年,月,今天 框*/
    .yearrow .yeararea, .yearrow .montharea, .yearrow .todayarea {
        position: relative;
        display: inline-block;
        width: 40%;
        height: 24px;
        line-height: 24px;
    }

    .yearrow .yeararea {
        width: 45%;
    }

    .yearrow .montharea {
        width: 35%;
    }

    .yearrow .todayarea {
        width: 20%;
    }
    /*年,月,今天 按鈕*/
    .yearrow .yearbtn, .yearrow .monthbtn, .yearrow .today {
        display: inline-block;
        font-size: 14px;
        font-weight: 600;
        width: 50%;
        height: 100%;
        border: 1px solid #eee;
        border-radius: 4px;
        vertical-align: middle;
        cursor: pointer;
        color:#292929;
    }

        .yearrow .yearbtn:hover, .yearrow .monthbtn:hover, .yearrow .today:hover {
            background-color: #eee;
        }

    .yearrow .today {
        width: auto;
        padding: 0 5px;
    }
    /*年月,前進後退按鈕*/
    .yearrow .prevbtn, .yearrow .nextbtn {
        display: inline-block;
        font-weight: 600;
        font-size: 18px;
        color: #999;
        width: 18px;
        height: 100%;
        border: 1px solid #eee;
        border-radius: 4px;
        vertical-align: middle;
    }

        .yearrow .prevbtn:hover, .yearrow .nextbtn:hover {
            color: #292929;
            cursor: pointer;
            background-color: #eee;
        }
    /*年月 選擇框*/
    .yearrow .yearsops, .yearrow .monthsops {
        position: absolute;
        top: 26px;
        left: 0;
        right: 0;
        box-sizing:border-box;
        border: 1px solid #bbb;
        border-radius: 4px;
        width: 80%;
        margin: 0 auto;
        border-top: none;
        z-index:9999;
        background-color: #fff;
    }
    .yearrow .yearsops{
        padding:5px;
        width: 90%;
        height:220px;
        overflow-x:hidden;
        overflow-y:scroll;
    }
    /*年份上下翻頁按鈕*/
    /*.yearrow .yearup,.yearrow .yeardown{
        position:absolute;
        font-size:24px;
        font-weight:600;
        width:20px;height:30px;
        right:5px;
        cursor:pointer;
        border-radius:4px;
        color:#999;
    }
    .yearrow .yearup:hover,.yearrow .yeardown:hover{
        color:#292929;
    }
    .yearrow .yearup{
        top:30%;
    }
    .yearrow .yeardown{
        top:45%;
    }*/

    /**/
        .yearrow .yearsops b, .yearrow .monthsops b {
            font-size: 13px;
            font-weight: 500;
            display: inline-block;
            border-radius: 4px;
            height: 28px;
            line-height: 28px;
            border-bottom:1px solid #eee;
        }

            .yearrow .yearsops b:hover, .yearrow .monthsops b:hover {
                background-color: #eee;
            }

        .yearrow .yearsops b {
            width: 50%;
        }

            .yearrow .yearsops b.selected, .yearrow .monthsops b.selected {
                background-color: #0996f8;
            }

        .yearrow .monthsops b {
            width: 50%;
        }


/*第2行,固定的星期*/
.weekrow b, .daysrow b {
    font-size: 13px;
    font-weight: 500;
    display: inline-block;
    width: 14.28571428%;
    height: 24px;
    line-height: 24px;
    padding: 4px 0;
}

    .weekrow b:first-child, .weekrow b:last-child, .daysrow b:first-child, .daysrow b:last-child {
        color: red;
    }
/*第3行 日*/
.daysrow b {
    border-radius: 4px;
}

    .daysrow b.today {
        color:#fff;
        background-color: #0996f8;
    }
    .daysrow b.selected{
        background-color: #ccc;
    }
    .daysrow b:not(.today):not(.selected):hover {
        background-color: #eee;
    }

.daysrow .dayoutmonth {
    opacity: .3;
}
mydate

JS日期選擇器