总想写点什么,可又没什么太多的原创东西,即使是原创但技术含量太低实在拿不出手,只好拿js大牛客服果果的号称最精简的日历代码分析一下,顺便完善了代码,该日历适合用于要求不是很苛刻的情况。
先看看第一段js原代码吧!
var $ = new Date( this );
$.setDate( 1 );
return $.getDay()
};
这段是对Date对象添加了原型方法fDay,该方法返回的是当前月份的第一天星期几,注意星期天就是返回0,setDate(1)设置日期格式为当前时间月份的第一天,getDay返回星期几。
var $ 1 = new Date( this ),$ 2 = new Date( this );
$ 1 .setDate( 1 );
$ 2 .setDate( 1 );
$ 2 .setMonth($ 2 .getMonth() + 1 );
return ($ 2 - $ 1 ) / 86400000;
};
第二段也是对Date对象添加了原型方法dCount,该方法返回的是当前月份共有多少天。程序第一行定义两个当前时间变量,然后分别设置为当前月份的第一天,然后把$2变量设置为当前月份的下一个月份,最后减去当前月份得到是一个月的毫秒数,除以一天的毫秒数得到当前月份的天数。
接下来是程序主体:
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
init: function (){
this .$ = new Date;
this .update();
document.onclick = function (e){
e = e || window.event;
var target = e.srcElement || e.target ;
if (target.parentNode.id != ' iCalendar_body ' && target.parentNode.id != ' iCalendar ' && target != CLD.$$)
CLD.getId( ' iCalendar ' ).style.display = " none " ;
};
return this
},
getId: function (id){
return typeof id === ' string ' ? document.getElementById(id):id;
},
update: function (y,m){
var uiList = [],week = ' 日一二三四五六 ' .split( '' ),$ = this .$,getId = this .getId,
fn = function (a,b){
return ' <b class="btn" οnclick="CLD.update( ' + a + ' )"> ' + b + ' </b> '
};
y && $.setYear($.getFullYear() + y);
m && $.setMonth($.getMonth() + m);
var Y = $.getFullYear(),M = $.getMonth() + 1 ,D = $.getDate();
for ( var i = 0 ;i < week.length;i ++ )uiList.push( ' <b> ' + week[i] + ' </b> ' );
for (i = 0 ;i < $.fDay();i ++ )uiList.push( ' <b> </b> ' );
for (i = 0 ;i < $.dCount();i ++ )uiList.push( ' <a href="javascript:CLD.set( ' + Y + ' , ' + M + ' , ' + (i + 1 ) + ' )"> ' + (i + 1 ) + ' </a> ' );
getId( ' iCalendar_body ' ).innerHTML = fn( ' -1,null ' , ' << ' ) + fn( ' null,-1 ' , ' < ' ) + ' <b id="dateCap"> ' + Y + ' 年 ' + M + ' 月</b> ' + fn( ' null,1 ' , ' > ' ) + fn( ' 1,null ' , ' >> ' ) + uiList.join( '' );
if ( this .$$) this .$$.focus();
getId( ' iCalendar_mask ' ).width = getId( ' iCalendar_body ' ).offsetWidth - 2 ;
getId( ' iCalendar_mask ' ).height = getId( ' iCalendar_body ' ).offsetHeight;
},
showTo: function (v){
for ( var pos = {x: 0 ,y: 0 },$ = v;v;v = v.offsetParent){
pos.x += v.offsetLeft;
pos.y += v.offsetTop
};
document.title = [pos.x,pos.y]
with ( this .getId( ' iCalendar ' ).style){
left = pos.x + " px " ;
top = (pos.y + $.offsetHeight) + " px " ;
display = ""
}
},
bind: function (x){
x.onfocus = function (){
CLD.$$ = this ;
CLD.showTo( this )
};
return this ;
},
set: function (y,m,d){
if (CLD.$$){
CLD.$$.value = y + ' - ' + m + ' - ' + d;
CLD.getId( ' iCalendar ' ).style.display = " none " ;
}
}
}).init().bind(CLD.getId( ' i_1 ' )).bind(CLD.getId( ' i_2 ' ))
作者使用闭包把程序主体封装在CLD这个命名空间下可以理解成一个对象,第一个方法是init用来初始化程序,主要是初始日期变量,并且调用了update方法,后面这个document.onlick事件是我改写的,原本作者的意图是让用户点击弹出的日历空白地方就隐藏,但我觉得不够合理就改成点击日历区域外的空间就才隐藏日历。如果事件触发的源dom对象包含在日历内(选中日期除外)则不不会隐藏。最后返回了自己也就是CLD这个对象,可以实现类似jQuery那样的链式操作。bind方法也是如此。
下面的getId方法也是我自己添加的,原本程序里是没有的,客服果果直接用id来操作dom,当时在网上直接访问他的代码在ff,ie下都没有问题,后来拷贝到本地运行发现ff下面提示id没定义,但是ie下可以正常运行,后来知道问题在于拷贝到本地的代码加了头部xhtml 1.0的dtd声明,于是ff就以严格模式解析js,直接使用id就报错,如果不声明的话ff会以html5的模式去解析,在ff的控制台下会有警告说明直接使用id不符合w3c标准,但不会报错导致程序无法运行。所以在此为了避免出现不可预料的麻烦还是多写一行代码使用getElementById吧!
紧跟着是程序的核心方法update,主要功能就是组装日历元素包括年月前后翻转按钮,空白b元素,可选的日期元素。week='日一二三四五六'.split('')这是种很巧妙的定义数组的办法,值得借鉴。然后又定义了fn这个方法后面复用的比较多,该方法返回一个b元素并且将update方法绑定到点击事件上,这个b元素就年月的前后加减的按钮。
m && $.setMonth($.getMonth() + m);
这两行是设置年,月并且判断输入的参数y和m是为null,后面会调用到。
将字符串“星期日”至”星期六“循环压入到uiList数组中。
将空白填充部分压入到uiList数组中。
将当前月份的天数循环压入到uiList数组中。
然后把组合的元素全部以字符串的形式连接起来并置于日历的body当中。
后面是设置iframe的高和宽用于解决ie6下面div无法遮住select元素的bug。
然后是showTo方法,顾名思义是用来显示日历的。主要是计算绑定input的实际位置把它的left直接赋值给日历控件,把top加上input的实际高度再赋值给日历并显示。
最后是bind方法,绑定onfocus事件,set方法将选中的日期赋值给input,用闭包直接调用了init方法然后将日历控件绑定到两个input上。
至此整个程序分析完毕,精简的日历也不简单,里面一些方法都是比较巧妙的设计高度的复用。当然实际项目中应用的日历功能肯定不会这么简陋,一般的功能如设定初始时间,限制输入的日期段,解出绑定控件等等,另外这个日历外层的div是直接写在页面上的,个人觉得也应该封装到js里面去便于移植,以后有时间再基于这个程序扩展和丰富功能。
这里是可以直接运行的代码(拷贝到本地另存为html文件即可)
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< meta http-equiv ="Content-Type" content ="text/html; charset=utf-8" />
< meta http-equiv ="X-UA-Compatible" content ="IE=EmulateIE7" />
< meta name ="copyright" content ="" />
< meta name ="keywords" content ="精简的日历控件" />
< meta name ="description" content ="精简的日历控件" />
< title > 日历 </ title >
< style >
#iCalendar { border : 1px solid #1F62BE ; border-top : 7px solid #208DDE ; width : 210px ; position : absolute ; font-family : Arial ; background : #F0F9FF ; left : -500px ; overflow : hidden ; }
#iCalendar_body { _height : 170px ; padding : 0 5px ; background : #F0F9FF }
#iCalendar iframe { position : absolute ; ;z-index : -1 ; top : 0 ; left : 0 ; background : #F0F9FF }
#iCalendar a,#iCalendar b { display : block ; float : left ; zoom : 1 ; width : 20px ; height : 16px ; line-height : 16px ; padding : 2px ; background : #F0F9FF ; font-size : 12px ; text-align : center ; color : #333 ; font-family : Arial ; text-decoration : none ; margin : 0px 2px ; }
#iCalendar b { background : none ; }
#iCalendar a:hover { background : #FE8B1A ; color : #fff ; font-weight : bold }
#iCalendar .btn { cursor : pointer ; width : 18px ; }
#iCalendar #dateCap { width : 80px ; color : #900 ; }
p { padding : 20px ; }
</ style >
</ head >
< body >
< p >
< div id ="iCalendar" tabIndex ='-1' >
< iframe id ="iCalendar_mask" src ="" frameBorder =0 ></ iframe >
< div id ="iCalendar_body" ></ div >
</ div >
< input type ="text" id ="i_1" />< input type ="text" id ="i_2" />< br />
< select id ="" >< option value ="" selected ="selected" > dhooo.com </ option ></ select >
</ p >
</ body >
</ html >
< script >
alert(i_1);
Date.prototype.fDay = function (){
var $ = new Date( this );
$.setDate( 1 );
return $.getDay()
};
Date.prototype.dCount = function (){
var $ 1 = new Date( this ),$ 2 = new Date( this );
$ 1 .setDate( 1 );
$ 2 .setDate( 1 );
$ 2 .setMonth($ 2 .getMonth() + 1 );
return ($ 2 - $ 1 ) / 86400000;
};
(CLD = {
init: function (){
this .$ = new Date;
this .update();
document.onclick = function (e){
e = e || window.event;
var target = e.srcElement || e.target ;
if (target.parentNode.id != ' iCalendar_body ' && target.parentNode.id != ' iCalendar ' && target != CLD.$$)
CLD.getId( ' iCalendar ' ).style.display = " none " ;
};
return this
},
getId: function (id){
return typeof id === ' string ' ? document.getElementById(id):id;
},
update: function (y,m){
var uiList = [],week = ' 日一二三四五六 ' .split( '' ),$ = this .$,getId = this .getId,
fn = function (a,b){
return ' <b class="btn" οnclick="CLD.update( ' + a + ' )"> ' + b + ' </b> '
};
y && $.setYear($.getFullYear() + y);
m && $.setMonth($.getMonth() + m);
var Y = $.getFullYear(),M = $.getMonth() + 1 ,D = $.getDate();
for ( var i = 0 ;i < week.length;i ++ )uiList.push( ' <b> ' + week[i] + ' </b> ' );
for (i = 0 ;i < $.fDay();i ++ )uiList.push( ' <b> </b> ' );
for (i = 0 ;i < $.dCount();i ++ )uiList.push( ' <a href="javascript:CLD.set( ' + Y + ' , ' + M + ' , ' + (i + 1 ) + ' )"> ' + (i + 1 ) + ' </a> ' );
getId( ' iCalendar_body ' ).innerHTML = fn( ' -1,null ' , ' << ' ) + fn( ' null,-1 ' , ' < ' ) + ' <b id="dateCap"> ' + Y + ' 年 ' + M + ' 月</b> ' + fn( ' null,1 ' , ' > ' ) + fn( ' 1,null ' , ' >> ' ) + uiList.join( '' );
if ( this .$$) this .$$.focus();
getId( ' iCalendar_mask ' ).width = getId( ' iCalendar_body ' ).offsetWidth - 2 ;
getId( ' iCalendar_mask ' ).height = getId( ' iCalendar_body ' ).offsetHeight;
},
showTo: function (v){
for ( var pos = {x: 0 ,y: 0 },$ = v;v;v = v.offsetParent){
pos.x += v.offsetLeft;
pos.y += v.offsetTop
};
document.title = [pos.x,pos.y]
with ( this .getId( ' iCalendar ' ).style){
left = pos.x + " px " ;
top = (pos.y + $.offsetHeight) + " px " ;
display = ""
}
},
bind: function (x){
x.onfocus = function (){
CLD.$$ = this ;
CLD.showTo( this )
};
return this ;
},
set: function (y,m,d){
if (CLD.$$){
CLD.$$.value = y + ' - ' + m + ' - ' + d;
CLD.getId( ' iCalendar ' ).style.display = " none " ;
}
}
}).init().bind(CLD.getId( ' i_1 ' )).bind(CLD.getId( ' i_2 ' ))
</ script >