<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)"><</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)">></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)"><</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)">></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();}
样式:
/*外框*/.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;}
JS日期选择器
原文地址:http://www.cnblogs.com/mirrortom/p/8093983.html