最近研究下JS日期級聯效果 感覺還不錯然後看了下kissy也正好有這麼一個組件也看了下源碼寫的還不錯通過google最早是在年 淘寶的虎牙(花名)用原審JS寫了一個(貌似據說是從YUI那邊重構下的) 具體的可以看他的 博客園 感覺kissy組件源碼 思路也是和YUI類似 所以我今天的基本思路也和他們的一樣 只是通過自己分析下及用自己的方式包裝下
基本原理
傳參中有 ;年份下拉框dom節點; ;月份下拉框dom節點; ;天數下拉框dom節點; "開始日期""結束日期""默認日期"配置項
如果開始傳參日期為空 那麼默認是從""開始
如果"結束日期為空" 那麼默認結束日期為當前的時間
如果默認日期為空 那麼默認日期默認為當前的時間
月份對應的天數可以直接寫死 如_dayInMonth: [ ] ; 分別為月份到月份的各個月份的默認天數當然還有月份閏年天的情況 待會在代碼中會有判斷的
分別渲染出年份區間月份區間及相應的天數(如果有默認的日期的話 且默認日期大於或者等於開始日期 且小於或者等於結束日期的話) 那麼頁面加載的時候 顯示默認日期
綁定change事件 當切換到不同年份的時候 月份和天數也要分別渲染出來
基本配置項如下
對外提供的方法
getDate() 返回當前時間格式為yyyymmdd
getYear() 返回當前的年份
getMonth() 返回當前的月份
getDay() 返回當前月份中的天數
JSFiddle demo鏈接如下
查看demo 請點擊我!
下面代碼分析如下
初始化調用init方法分別獲取開始時間 結束時間 默認時間的 "年月天"如下代碼
// 開始時間可選 如果為空的話 那麼默認開始時間是
if(_configdateStart != ) {
thisstartDate = {
y: new Date(_configdateStart)getFullYear()
m: new Date(_configdateStart)getMonth() +
d: new Date(_configdateStart)getDate()
};
}else {
var dateStart = //;
thisstartDate = {
y: new Date(dateStart)getFullYear()
m: new Date(dateStart)getMonth() +
d: new Date(dateStart)getDate()
};
}
// dateEnd 默認為空 如果沒有傳入的話 就取當前的時間
if(_configdateEnd == ) {
thisendDate = {
y: new Date()getFullYear()
m: new Date()getMonth() +
d: new Date()getDate()
};
}else {
thisendDate = {
y: new Date(_configdateEnd)getFullYear()
m: new Date(_configdateEnd)getMonth() +
d: new Date(_configdateEnd)getDate()
};
}
// 默認時間可選 如果默認時間為空的話 那麼就取當前的時間
if(_configdateDefault != ) {
thisdefaultDate = {
y: new Date(_configdateDefault)getFullYear()
m: new Date(_configdateDefault)getMonth() +
d: new Date(_configdateDefault)getDate()
};
}else {
thisdefaultDate = {
y: new Date()getFullYear()
m: new Date()getMonth() +
d: new Date()getDate()
};
}
// 判斷時間是否合理
if((Dateparse(self_changeFormat(_configdateStart)) > Dateparse(self_changeFormat(_configdateEnd))) ||
(Dateparse(self_changeFormat(_configdateDefault)) > Dateparse(self_changeFormat(_configdateEnd)))){
return;
}
渲染下拉框的年份調用 y = self_renderYear();這個方法
獲取年份的區間范圍獲取方法就是獲取開始時間的年份 和 結束時的年份 如下代碼
/*
* 獲取年份的范圍 最小最大
* @method _getYearRange
* @return {minmax}
*/
_getYearRange: function(){
var self = this
_config = nfig;
return {
min: selfstartDatey
max: selfendDatey
}
}
接著渲染年份從最近的年份開始渲染如果有默認的年份 且 滿足條件的話 那麼默認的年份顯示出來如下代碼
/*
* 渲染年份下拉框
* @method _renderYear
* private
*/
_renderYear: function(){
var self = this
_config = nfig
_cache = selfcache;
var nodeyear = $(_confignodeYear)[]
y = selfdefaultDatey
range
option;
if(nodeyear) {
range = self_getYearRange();
for(var i = rangemax; i >= rangemin; i) {
option = new Option(ii);
// 如果有默認年份的話
if(i == y) {
optionselected = true;
}
// 兼容所有浏覽器 插入到最後
nodeyearadd(optionundefined);
}
}
$(nodeyear)attr(yeary);
return y;
}
接著渲染月份 調用這個方法 y參數就是剛剛返回的年份 m = self_renderMonth(y);
同理 渲染月份也要獲取月份的范圍 默認都是從月份到月份 但是也有列外比如如下個判斷
/*
* 獲取月份的范圍
* @method _getMonthRange
* @param {y} Number
*/
_getMonthRange: function(y){
var self = this
_config = nfig;
var startDate = selfstartDate
endDate = selfendDate
min =
max = ;
/*
* 如果默認年份等於開始年份的話 那麼月份最小取得是開始的月份
* 因為如果開始是 如果默認的是 那麼最小月份肯定取得是
* 因為默認時間不可能小於開始時間
*/
if(y == startDatey) { // 開始年份
min = startDatem;
}
/*
* 同理 如果默認年份等於 那麼取得是當前的年份(endDate未傳的情況下)
* 那麼最大的肯定取得是當前年份的 月份 不可能取的是 因為只渲染出當前月份出來
* 後面的月份沒有渲染出來
*/
if(y == endDatey) {
max = endDatem;
}
return {
min: min
max: max
}
}
知道月份的范圍後 然後根據上面的年份渲染相應的月份代碼如下
/*
* 根據年份 渲染所有的月份
* @method _renderMonth
* @param {y} 年份
*/
_renderMonth: function(y){
var self = this
_config = nfig;
var nodeMonth = $(_confignodeMonth)[]
m = $(nodeMonth)attr(month) || selfdefaultDatem
range
option
t = false;
if(nodeMonth) {
range = self_getMonthRange(y);
nodeMonthinnerHTML = ;
for(var i = rangemin; i <= rangemax; i++) {
option = new Option(selfbitExpand(i)selfbitExpand(i));
// 如果有默認的月份的話
if(i == m) {
optionselected = true;
m = i;
t = true;
}
// 兼容所有浏覽器 插入到最後
nodeMonthadd(optionundefined);
}
if(!t) {
m = rangemin;
}
}
$(nodeMonth)attr(monthm);
return m;
}
上面的代碼 用了這句判斷 m = $(nodeMonth)attr(;month;) || selfdefaultDatem 默認情況下 也就是說頁面一加載的時候 可以獲取默認的月份但是當我觸發change事件後 我取的月份 是從m = $(nodeMonth)attr(;month;) 這個裡面取得上面代碼 nodeMonthinnerHTML = ;;; 也是為了change時候 請清空掉 然後重新生成的
渲染天數 通過這個方法 self_renderDay(ym);
渲染天數 同理也要獲得相應的天數調用_getDayRange方法此方法中有判斷是閏年的情況的如下代碼
/*
* 獲得天數的范圍
* @method _getDayRange
* @param {ym} {numbernumber}
*/
_getDayRange: function(ym){
var self = this
_config = nfig
_cache = selfcache;
var startDate = selfstartDate
endDate = selfendDate
min =
max;
if(m) {
if(m == ) {
max = self_isLeapYear(y) ? : ;
}else {
max = _cache_dayInMonth[m];
}
// 如果年月份都等於開始日期的話 那麼min也等於開始日
if(y == startDatey && m == startDatem) {
min = startDated;
}
// 如果年月份都等於結束日期的話 那麼max也等於結束日
if(y == endDatey && m == endDatem) {
max = endDated;
}
}
return {
min: min
max: max
}
}
接著渲染天數的方法如下
_renderDay: function(ym) {
var self = this
_config = nfig;
var nodeDay = $(_confignodeDay)[]
d = $(nodeDay)attr(day) || selfdefaultDated
range
option
t = false;
if(nodeDay) {
range = self_getDayRange(ym);
nodeDayinnerHTML = ;
for(var i = rangemin; i <= rangemax; i++) {
option = new Option(selfbitExpand(i)selfbitExpand(i));
// 如果有默認的天數的話
if(i == d) {
optionselected = true;
d = i;
t = true;
}
// 兼容所有浏覽器 插入到最後
nodeDayadd(optionundefined);
}
if(!t) {
d = rangemin;
}
}
$(nodeDay)attr(dayd);
return d;
}
最後用綁定change事件 調用_bindEnv方法如
/*
* 綁定所有事件
* @method _bindEnv
* private
*/
_bindEnv:function(){
var self = this
_config = nfig
_cache = selfcache;
//年份改變
$(_confignodeYear)change(function(e){
var y = etargetvalue
m = self_renderMonth(y);
self_renderDay(ym);
$(_confignodeYear)attr(yeary);
});
//月份改變
$(_confignodeMonth)change(function(e){
var m = etargetvalue
y = $(_confignodeYear)attr(year);
self_renderDay(ym);
$(_confignodeMonth)attr(monthm);
});
//日期改變
$(_confignodeDay)change(function(e){
var d = etargetvalue;
$(_confignodeDay)attr(dayd);
});
}
HTML代碼如下
<label>出生日期: </label>
<select id=year> </select>年
<select id=month> </select>月
<select id=day> </select>日
<ul>
<li><em>getDate</em> : <button id=testDate>日期</button><input id=textDate/></li>
<li><em>getYear</em> : <button id=testYear>年</button><input id=textYear/></li>
<li><em>getMonth</em> : <button id=testMonth>月</button><input id=textMonth/></li>
<li><em>getDay</em> : <button id=testDay>日</button><input id=textDay/></li>
</ul>
JS代碼如下
/**
* JS日期級聯組件
* @constructor DateCascade
* @param {object} 可配置的對象
* @time
* @author
*/
function DateCascade(options) {
nfig = {
nodeYear : #year // 年份下拉框dom
nodeMonth : #month // 月份下拉框dom
nodeDay : #day // 日期下拉框dom
dateStart : // 開始日期
dateEnd : // 結束日期(可選 默認為空就為當前時間)
dateDefault : // 默認日期
};
thiscache = {
_dayInMonth: [ ] // 月份對應的天數
};
thisinit(options);
}
DateCascadeprototype = {
constructor: DateCascade
init: function(options) {
nfig = $extend(nfigoptions || {});
var self = this
_config = nfig
_cache = selfcache;
var y
m;
/* 開始時間 和 截至時間 默認時間*/
// 開始時間可選 如果為空的話 那麼默認開始時間是
if(_configdateStart != ) {
thisstartDate = {
y: new Date(_configdateStart)getFullYear()
m: new Date(_configdateStart)getMonth() +
d: new Date(_configdateStart)getDate()
};
}else {
var dateStart = //;
thisstartDate = {
y: new Date(dateStart)getFullYear()
m: new Date(dateStart)getMonth() +
d: new Date(dateStart)getDate()
};
}
// dateEnd 默認為空 如果沒有傳入的話 就取當前的時間
if(_configdateEnd == ) {
thisendDate = {
y: new Date()getFullYear()
m: new Date()getMonth() +
d: new Date()getDate()
};
}else {
thisendDate = {
y: new Date(_configdateEnd)getFullYear()
m: new Date(_configdateEnd)getMonth() +
d: new Date(_configdateEnd)getDate()
};
}
// 默認時間可選 如果默認時間為空的話 那麼就取當前的時間
if(_configdateDefault != ) {
thisdefaultDate = {
y: new Date(_configdateDefault)getFullYear()
m: new Date(_configdateDefault)getMonth() +
d: new Date(_configdateDefault)getDate()
};
}else {
thisdefaultDate = {
y: new Date()getFullYear()
m: new Date()getMonth() +
d: new Date()getDate()
};
}
// 判斷時間是否合理
if((Dateparse(self_changeFormat(_configdateStart)) > Dateparse(self_changeFormat(_configdateEnd))) ||
(Dateparse(self_changeFormat(_configdateDefault)) > Dateparse(self_changeFormat(_configdateEnd)))){
return;
}
// 渲染年份
y = self_renderYear();
// 渲染月份
m = self_renderMonth(y);
// 渲染天
self_renderDay(ym);
// 所有綁定事件
self_bindEnv();
}
/*
* 渲染年份下拉框
* @method _renderYear
* private
*/
_renderYear: function(){
var self = this
_config = nfig
_cache = selfcache;
var nodeyear = $(_confignodeYear)[]
y = selfdefaultDatey
range
option;
if(nodeyear) {
range = self_getYearRange();
for(var i = rangemax; i >= rangemin; i) {
option = new Option(ii);
// 如果有默認年份的話
if(i == y) {
optionselected = true;
}
// 兼容所有浏覽器 插入到最後
nodeyearadd(optionundefined);
}
}
$(nodeyear)attr(yeary);
return y;
}
/*
* 根據年份 渲染所有的月份
* @method _renderMonth
* @param {y} 年份
*/
_renderMonth: function(y){
var self = this
_config = nfig;
var nodeMonth = $(_confignodeMonth)[]
m = $(nodeMonth)attr(month) || selfdefaultDatem
range
option
t = false;
if(nodeMonth) {
range = self_getMonthRange(y);
nodeMonthinnerHTML = ;
for(var i = rangemin; i <= rangemax; i++) {
option = new Option(selfbitExpand(i)selfbitExpand(i));
// 如果有默認的月份的話
if(i == m) {
optionselected = true;
m = i;
t = true;
}
// 兼容所有浏覽器 插入到最後
nodeMonthadd(optionundefined);
}
if(!t) {
m = rangemin;
}
}
$(nodeMonth)attr(monthm);
return m;
}
_renderDay: function(ym) {
var self = this
_config = nfig;
var nodeDay = $(_confignodeDay)[]
d = $(nodeDay)attr(day) || selfdefaultDated
range
option
t = false;
if(nodeDay) {
range = self_getDayRange(ym);
nodeDayinnerHTML = ;
for(var i = rangemin; i <= rangemax; i++) {
option = new Option(selfbitExpand(i)selfbitExpand(i));
// 如果有默認的天數的話
if(i == d) {
optionselected = true;
d = i;
t = true;
}
// 兼容所有浏覽器 插入到最後
nodeDayadd(optionundefined);
}
if(!t) {
d = rangemin;
}
}
$(nodeDay)attr(dayd);
return d;
}
/*
* 綁定所有事件
* @method _bindEnv
* private
*/
_bindEnv:function(){
var self = this
_config = nfig
_cache = selfcache;
//年份改變
$(_confignodeYear)change(function(e){
var y = etargetvalue
m = self_renderMonth(y);
self_renderDay(ym);
$(_confignodeYear)attr(yeary);
});
//月份改變
$(_confignodeMonth)change(function(e){
var m = etargetvalue
y = $(_confignodeYear)attr(year);
self_renderDay(ym);
$(_confignodeMonth)attr(monthm);
});
//日期改變
$(_confignodeDay)change(function(e){
var d = etargetvalue;
$(_confignodeDay)attr(dayd);
});
}
/*
* 獲取年份的范圍 最小最大
* @method _getYearRange
* @return {minmax}
*/
_getYearRange: function(){
var self = this
_config = nfig;
return {
min: selfstartDatey
max: selfendDatey
}
}
/*
* 獲取月份的范圍
* @method _getMonthRange
* @param {y} Number
*/
_getMonthRange: function(y){
var self = this
_config = nfig;
var startDate = selfstartDate
endDate = selfendDate
min =
max = ;
/*
* 如果默認年份等於開始年份的話 那麼月份最小取得是開始的月份
* 因為如果開始是 如果默認的是 那麼最小月份肯定取得是
* 因為默認時間不可能小於開始時間
*/
if(y == startDatey) { // 開始年份
min = startDatem;
}
/*
* 同理 如果默認年份等於 那麼取得是當前的年份(endDate未傳的情況下)
* 那麼最大的肯定取得是當前年份的 月份 不可能取的是 因為只渲染出當前月份出來
* 後面的月份沒有渲染出來
*/
if(y == endDatey) {
max = endDatem;
}
return {
min: min
max: max
}
}
/*
* 獲得天數的范圍
* @method _getDayRange
* @param {ym} {numbernumber}
*/
_getDayRange: function(ym){
var self = this
_config = nfig
_cache = selfcache;
var startDate = selfstartDate
endDate = selfendDate
min =
max;
if(m) {
if(m == ) {
max = self_isLeapYear(y) ? : ;
}else {
max = _cache_dayInMonth[m];
}
// 如果年月份都等於開始日期的話 那麼min也等於開始日
if(y == startDatey && m == startDatem) {
min = startDated;
}
// 如果年月份都等於結束日期的話 那麼max也等於結束日
if(y == endDatey && m == endDatem) {
max = endDated;
}
}
return {
min: min
max: max
}
}
/*
* 判斷是否是閏年
*/
_isLeapYear: function(y){
return (y % === && y % !== ) || (y % === );
}
/**
* 是否是Date格式
* @method _isDate
* @param {Date} d
* @private
* @return {Boolean}
*/
_isDate: function(d){
return ObjectprototypetoStringcall(d) === [object Date] && dtoString() !== Invalid Date && !isNaN(d);
}
/*
* 小於的數字加零
* @method bitExpand
*/
bitExpand: function(num) {
var num = num * ;
if(/d/test(num)) {
if(num < ) {
return + num;
}else {
return num;
}
}
}
/*
* 判斷開始日期 默認日期 結束日期的格式
*/
_changeFormat: function(date) {
return datereplace(//g/);
}
/*
* 獲取日期
*/
getDate: function(){
var self = this
_config = nfig;
var year = $(_confignodeYear)attr(year)
month = $(_confignodeMonth)attr(month)
day = $(_confignodeDay)attr(day);
return (year + + selfbitExpand(month) + + selfbitExpand(day));
}
/*
* 獲取年份
*/
getYear: function(){
var self = this
_config = nfig;
var year = $(_confignodeYear)attr(year);
return year;
}
/*
* 獲取月份
*/
getMonth: function(){
var self = this
_config = nfig;
var month = $(_confignodeMonth)attr(month);
return month;
}
/*
* 獲取天數
*/
getDay: function(){
var self = this
_config = nfig;
var day = $(_confignodeDay)attr(day);
return day;
}
}
初始化方式如下
// 初始化
$(function(){
var date = new DateCascade({});
$(#testDate)click(function(e){
$(#textDate)val(dategetDate());
});
$(#testYear)click(function(e){ $(#textYear)val(datebitExpand(dategetYear()));
});
$(#testMonth)click(function(e){
$(#textMonth)val(datebitExpand(dategetMonth()));
});
$(#testDay)click(function(e){
$(#textDay)val(datebitExpand(dategetDay()));
});
});
DEMO下載
From:http://tw.wingwit.com/Article/program/Web/201405/30982.html