JS学习之一个简易的日历控件


Posted in Javascript onMarch 24, 2010

这个日历控件类似于园子用的日历,如下图:

JS学习之一个简易的日历控件  

 这种日历控件实现起来不难,下面简单分析下我的思路:

 首先,是该控件的可配置项:

... 
settings: 
{ 
firstDayOfWeek: 1, 
baseClass: "calendar", 
curDayClass: "curDay", 
prevMonthCellClass: "prevMonth", 
nextMonthCellClass: "nextMonth", 
curMonthNormalCellClass: "", 
prevNextMonthDaysVisible: true 
}, 
... 
weekDayNames: [], 
...

    其中有一半是用来控制单元格样式的(不做过多描述),另外几个(firstDayOfWeek,prevNextMonthDaysVisible,weekDayNames),意义如下:
     firstDayOfWeek:日历以星期几做为第一天
     prevNextMonthDaysVisible:是否显示本月之外的日期
     weekDayNames:星期的名称(一个索引从1开始的数组,1处的值将作为周一的显示名称,以此类推)

     接下来,进入生成html代码阶段:
    1.生成日历头:    

_RenderTitle: function(month, year) { 
var ht = []; 
//日期 
ht.push("<tr>"); 
ht.push("<th colspan='7' style='width:100%;'><div style='float:left;width:10%;text-align:center;' id='", this.containerId, "_prevMonth' title='上一月'><</div><div style='float:left;text-align:center;width:80%'>", year, "年", month, "月</div><div style='float:right;width:10%; text-align:center;' id='", this.containerId, "_nextMonth' title='下一月'>></div></th>"); 
ht.push("</tr>"); 
//星期 
ht.push("<tr>"); 
for (var i = 0; i < 7; i++) { 
var day = (i + this.settings.firstDayOfWeek) == 7 ? 7 : (i + this.settings.firstDayOfWeek) % 7; 
ht.push("<th>", this.weekDayNames[day], "</th>") 
} 
ht.push("</tr>"); 
return ht.join(""); 
},

    日期部分为操作‘按钮'的id使用日历控件容器的id 作为前缀,以保证id唯一。
    星期部分根据firstDayOfWeek的设置来获取weekDayName。这里关键在于判断每个单元格代表星期几,思路很简单:
    var day = (i + this.settings.firstDayOfWeek) == 7 ? 7 : (i + this.settings.firstDayOfWeek) % 7;
    这样就可以取得当前单元格代表的星期了。

    2.生成日历的主要部分:

_RenderBody: function(month, year) { 
var date = new Date(year, month - 1, 1); 
var day = date.getDay(); 
var dayOfMonth = 1; 
var daysOfPrevMonth = (7 - this.settings.firstDayOfWeek + day) % 7; 
var totalDays = this._GetTotalDays(month, year); 
var totalDaysOfPrevMonth = this._GetToalDaysOfPrevMonth(month, year); 
var ht = []; 
var curDate; 
for (var i = 0; ; i++) { 
curDate = null; 
if (i % 7 == 0) {//新起一行 
ht.push("<tr>"); 
} 
ht.push("<td"); 
if (i >= daysOfPrevMonth && dayOfMonth <= totalDays) {//本月 
curDate = new Date(year, month - 1, dayOfMonth); 
if (Date.parse(new Date().toDateString()) - curDate == 0) { 
ht.push(" class='", this.settings.curDayClass, "'"); 
} 
else { 
ht.push(" class='", this.settings.curMonthNormalCellClass, "'"); 
} 
dayOfMonth++; 
} 
else if (i < daysOfPrevMonth) {//上月 
if (this.settings.prevNextMonthDaysVisible) { 
var prevMonth = month; 
var prevYear = year; 
if (month == 1) { 
prevMonth = 12; 
prevYear = prevYear - 1; 
} 
else { 
prevMonth = prevMonth - 1; 
} 
curDate = new Date(prevYear, prevMonth - 1, totalDaysOfPrevMonth - (daysOfPrevMonth - i - 1)); 
ht.push(" class='", this.settings.prevMonthCellClass, "'"); 
} 
} 
else {//下月 
if (this.settings.prevNextMonthDaysVisible) { 
var nextMonth = month; 
var nextYear = year; 
if (month == 12) { 
nextMonth = 1; 
nextYear = prevYear + 1; 
} 
else { 
nextMonth = nextMonth + 1; 
} 
curDate = new Date(nextYear, nextMonth-1, i - dayOfMonth - daysOfPrevMonth + 2); 
ht.push(" class='", this.settings.nextMonthCellClass, "'"); 
} 
} 
ht.push(">"); 
ht.push(this._BuildCell(curDate)); 
ht.push("</td>"); 
if (i % 7 == 6) {//结束一行 
ht.push("</tr>"); 
} 
if (i % 7 == 6 && dayOfMonth - 1 >= totalDays) { 
break; 
} 
} 
return ht.join(""); 
},

    (1).获取该月一号代表星期几。这样才能判断1号应该放到哪个单元格,也就是该月从哪个单元格开始(创建日期的时候month减了1,这是由于js Date对象本身的特性)。
    (2).定义了一个标识变量 dayOfMonth ,用于控制本月日期显示区域。
    (3).计算要展示的上月的天数以及上月的总天数(不用计算下月要展示的天数和总天数,因为下月要展示的日期是从1开始,最多不会超过6)。
    (4).显示本月的日期:
    条件i >= daysOfPrevMonth && dayOfMonth <= totalDays决定了本月日期的显示区域。
    (5).显示上月日期:
    当i < daysOfPrevMonth 时即为上月日期的显示区域。
    (6). (4)、(5)之外当然就是下月日期的显示区域了。
    (7).何时结束:
     从代码看到for循环是没有终止条件的,因此必须自己决定何时退出循环:
     if (i % 7 == 6 && dayOfMonth - 1 >= totalDays) { 
break; 
}

     i % 7 == 6表示一行结束, dayOfMonth - 1 >= totalDays表示本月日期已经展示完毕。
    (8).构造curDate:
curDate代表每个单元格对应的日期。
在显示本月日期时, curDate = new Date(year, month - 1, dayOfMonth);
在显示上月日期时, curDate = new Date(prevYear, prevMonth-1, totalDaysOfPrevMonth - (daysOfPrevMonth - i - 1));
在显示下月日期时, curDate = new Date(nextYear, nextMonth-1, i - dayOfMonth - daysOfPrevMonth + 2),加2是由于i是从0开始,本身就少了1,dayOfMonth 在退出显示本月日期时多加了一次.
    最后,再来看看_BuildCell做了什么事情:
_BuildCell: function(curDate) { 
var ht = []; 
if (curDate) { 
for (var j = 0; j < this.dateLinkMappings.length; j++) { 
if (Date.parse(this.dateLinkMappings[j].Date) - curDate == 0) { 
ht.push("<a href='", this.dateLinkMappings[j].Link, "'>", curDate.getDate(), "</a>"); 
break; 
} 
} 
if (j == this.dateLinkMappings.length) { 
ht.push(curDate.getDate()); 
} 
} 
else { 
ht.push(" "); 
} 
return ht.join(""); 
},

    事实上本日历控件的意图是用户可以在初始化时传入日期和该日期对应的链接的映射的数组,也就是this.dateLinkMappings,当构建单元格时若正在构建的日期包含在this.dateLinkMappings里,则将当前单元格构造成<a>形式,否则为普通的文本形式。

    OK,实现逻辑大致如此,篇末看下演示效果:
前台调用代码如下:

var date = new Date(); 
var mapping = []; 
mapping.push(new DateLinkMapping("3-22-2010", "javascript:alert(1)")); 
mapping.push(new DateLinkMapping("4-1-2010", "javascript:alert(1)")) 
Calendar.Init(null, mapping); 
Calendar.RenderCalendar("myCalendar", date.getMonth() + 1, date.getFullYear());

打包下载地址
Javascript 相关文章推荐
JavaScript事件列表解说
Dec 22 Javascript
javascript应用:Iframe自适应其加载的内容高度
Apr 10 Javascript
Javascript 中的 &amp;&amp; 和 || 使用小结
Apr 25 Javascript
lyhucSelect基于Jquery的Select数据联动插件
Mar 29 Javascript
JS 获取select(多选下拉)中所选值的示例代码
Aug 02 Javascript
JavaScript 中的日期和时间及表示标准介绍
Aug 21 Javascript
JQuery1.8 判断元素是否绑定事件的方法
Jul 10 Javascript
jQuery实现点击小图显示大图代码分享
Aug 25 Javascript
原生js实现class的添加和删除简单代码
Jul 12 Javascript
浅谈Webpack4 Tree Shaking 终极优化指南
Nov 18 Javascript
extjs4图表绘制之折线图实现方法分析
Mar 06 Javascript
html实现随机点名器的示例代码
Apr 02 Javascript
javascript instanceof,typeof的区别
Mar 24 #Javascript
ExtJs使用IFrame的实现代码
Mar 24 #Javascript
JS 显示当前日期与时间的代码
Mar 24 #Javascript
jQuery EasyUI 开源插件套装 完全替代ExtJS
Mar 24 #Javascript
锋利的jQuery 要点归纳(三) jQuery中的事件和动画(下:动画篇)
Mar 24 #Javascript
锋利的jQuery 要点归纳(三) jQuery中的事件和动画(上:事件篇)
Mar 24 #Javascript
jQuery AJAX 调用WebService实现代码
Mar 24 #Javascript
You might like
php多功能图片处理类分享(php图片缩放类)
2014/03/14 PHP
PHP中的流(streams)浅析
2015/07/02 PHP
PHP后期静态绑定实例浅析
2018/12/21 PHP
用PHP做了一个领取优惠券活动的示例代码
2019/07/05 PHP
php桥接模式应用案例分析
2019/10/23 PHP
JS 参数传递的实际应用代码分析
2009/09/13 Javascript
js简单实现标签云效果实例
2015/08/06 Javascript
纯js三维数组实现三级联动效果
2017/02/07 Javascript
前端页面文件拖拽上传模块js代码示例
2017/05/19 Javascript
JS实现json的序列化和反序列化功能示例
2017/06/13 Javascript
vue里面v-bind和Props 利用props绑定动态数据的方法
2018/08/27 Javascript
js遍历详解(forEach, map, for, for...in, for...of)
2019/08/28 Javascript
JavaScript实现音乐导航效果
2020/11/19 Javascript
JS操作JSON常用方法(10w阅读)
2020/12/06 Javascript
[01:55]2014DOTA2国际邀请赛快报:国土生病 紧急去医院治疗
2014/07/10 DOTA
[00:56]2014DOTA2国际邀请赛 DK、iG 赛前探访
2014/07/10 DOTA
简单介绍Python中的JSON使用
2015/04/28 Python
Python进程间通信用法实例
2015/06/04 Python
简要讲解Python编程中线程的创建与锁的使用
2016/02/28 Python
Python调用SQLPlus来操作和解析Oracle数据库的方法
2016/04/09 Python
Python安装lz4-0.10.1遇到的坑
2018/05/20 Python
python实战串口助手_解决8串口多个发送的问题
2019/06/12 Python
详解Python 调用C# dll库最简方法
2019/06/20 Python
python DES加密与解密及hex输出和bs64格式输出的实现代码
2020/04/13 Python
python实现与redis交互操作详解
2020/04/21 Python
python中not、and和or的优先级与详细用法介绍
2020/11/03 Python
python自动化办公操作PPT的实现
2021/02/05 Python
深入解析HTML5中的Blob对象的使用
2015/09/08 HTML / CSS
心理健康课教学反思
2014/02/13 职场文书
2014年公司庆元旦活动方案
2014/03/05 职场文书
任命书怎么写
2014/06/04 职场文书
单位活动策划方案
2014/08/17 职场文书
学习十八大演讲稿
2014/09/15 职场文书
2014大学校园光棍节活动策划书
2014/09/29 职场文书
幼儿园国庆节活动总结
2015/03/23 职场文书
详解TypeScript的基础类型
2022/02/18 Javascript