一个简单日历控件的分析

总想写点什么,可又没什么太多的原创东西,即使是原创但技术含量太低实在拿不出手,只好拿js大牛客服果果的号称最精简的日历代码分析一下,顺便完善了代码,该日历适合用于要求不是很苛刻的情况。

先看看第一段js原代码吧!

 

 
  
Date.prototype.fDay = function (){
var $ = new Date( this );
$.setDate(
1 );
return $.getDay()
};

这段是对Date对象添加了原型方法fDay,该方法返回的是当前月份的第一天星期几,注意星期天就是返回0,setDate(1)设置日期格式为当前时间月份的第一天,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;
};

第二段也是对Date对象添加了原型方法dCount,该方法返回的是当前月份共有多少天。程序第一行定义两个当前时间变量,然后分别设置为当前月份的第一天,然后把$2变量设置为当前月份的下一个月份,最后减去当前月份得到是一个月的毫秒数,除以一天的毫秒数得到当前月份的天数。

 

接下来是程序主体:

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
(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>&nbsp;</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 ' , ' &lt;&lt; ' ) + fn( ' null,-1 ' , ' &lt; ' ) + ' <b id="dateCap"> ' + Y + ' ' + M + ' 月</b> ' + fn( ' null,1 ' , ' &gt ' ) + fn( ' 1,null ' , ' &gt;&gt; ' ) + 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元素就年月的前后加减的按钮。

 

 
  
y && $.setYear($.getFullYear() + y);
m
&& $.setMonth($.getMonth() + m);

这两行是设置年,月并且判断输入的参数y和m是为null,后面会调用到。

 

 

 
  
for ( var i = 0 ;i < week.length;i ++ )uiList.push( ' <b> ' + week[i] + ' </b> ' );

将字符串“星期日”至”星期六“循环压入到uiList数组中。

 

 

 
  
for (i = 0 ;i < $.fDay();i ++ )uiList.push( ' <b>&nbsp;</b> ' );

将空白填充部分压入到uiList数组中。

 

 

 
  
for (i = 0 ;i < $.dCount();i ++ )uiList.push( ' <a href="javascript:CLD.set( ' + Y + ' , ' + M + ' , ' + (i + 1 ) + ' )"> ' + (i + 1 ) + ' </a> ' );

将当前月份的天数循环压入到uiList数组中。

 

 

 
  
getId( ' iCalendar_body ' ).innerHTML = fn( ' -1,null ' , ' &lt;&lt; ' ) + fn( ' null,-1 ' , ' &lt; ' ) + ' <b id="dateCap"> ' + Y + ' ' + M + ' 月</b> ' + fn( ' null,1 ' , ' &gt ' ) + fn( ' 1,null ' , ' &gt;&gt; ' ) + uiList.join( '' );

然后把组合的元素全部以字符串的形式连接起来并置于日历的body当中。

 

后面是设置iframe的高和宽用于解决ie6下面div无法遮住select元素的bug。

然后是showTo方法,顾名思义是用来显示日历的。主要是计算绑定input的实际位置把它的left直接赋值给日历控件,把top加上input的实际高度再赋值给日历并显示。

最后是bind方法,绑定onfocus事件,set方法将选中的日期赋值给input,用闭包直接调用了init方法然后将日历控件绑定到两个input上。

至此整个程序分析完毕,精简的日历也不简单,里面一些方法都是比较巧妙的设计高度的复用。当然实际项目中应用的日历功能肯定不会这么简陋,一般的功能如设定初始时间,限制输入的日期段,解出绑定控件等等,另外这个日历外层的div是直接写在页面上的,个人觉得也应该封装到js里面去便于移植,以后有时间再基于这个程序扩展和丰富功能。

这里是可以直接运行的代码(拷贝到本地另存为html文件即可)

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
<! DOCTYPE >
< 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>&nbsp;</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 ' , ' &lt;&lt; ' ) + fn( ' null,-1 ' , ' &lt; ' ) + ' <b id="dateCap"> ' + Y + ' ' + M + ' 月</b> ' + fn( ' null,1 ' , ' &gt ' ) + fn( ' 1,null ' , ' &gt;&gt; ' ) + 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 >

 

转载于:https://www.cnblogs.com/foot3188/archive/2010/09/17/1829339.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值