码迷,mamicode.com
首页 > Web开发 > 详细

JS日期选择器

时间:2017-12-23 20:16:59      阅读:408      评论:0      收藏:0      [点我收藏+]

标签:style   flow   mat   weight   btn   overflow   opened   后退   isl   

<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日期选择器

标签:style   flow   mat   weight   btn   overflow   opened   后退   isl   

原文地址:http://www.cnblogs.com/mirrortom/p/8093983.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!