JS日期選擇器
阿新 • • 發佈:2017-12-23
指定 腳本 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.jsmydate.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; }mydate
JS日期選擇器