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 相关文章推荐
表单序列化与jq中的serialize使用示例
Feb 21 Javascript
js实现绿白相间竖向网页百叶窗动画切换效果
Mar 02 Javascript
javascript实现仿IE顶部的可关闭警告条
May 05 Javascript
AngularJS基础 ng-mouseover 指令简单示例
Aug 02 Javascript
Bootstrap精简教程中秋大放送
Sep 15 Javascript
JavaScript简单拖拽效果(1)
May 17 Javascript
JS身份证信息验证正则表达式
Jun 12 Javascript
JS设置手机验证码60s等待实现代码
Jun 14 Javascript
Bootstrap table使用方法汇总
Nov 17 Javascript
React中如何引入Angular组件详解
Aug 09 Javascript
JS实现字符串翻转的方法分析
Aug 31 Javascript
Element-UI中关于table表格的那些骚操作(小结)
Aug 15 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
JS中encodeURIComponent函数用php解码的代码
2012/03/01 PHP
PHP面向对象程序设计(OOP)之方法重写(override)操作示例
2018/12/21 PHP
Laravel5.1 框架表单验证操作实例详解
2020/01/07 PHP
用js实现手把手教你月入万刀(转贴)
2007/11/07 Javascript
JS 密码强度验证(兼容IE,火狐,谷歌)
2010/03/15 Javascript
基于JQuery实现的类似购物商城的购物车
2011/12/06 Javascript
Javascript 面向对象(三)接口代码
2012/05/23 Javascript
js将字符串转成正则表达式的实现方法
2013/11/13 Javascript
JavaScript作用域链示例分享
2014/05/27 Javascript
AMD异步模块定义介绍和Require.js中使用jQuery及jQuery插件的方法
2014/06/06 Javascript
js+html5实现可在手机上玩的拼图游戏
2015/07/17 Javascript
整理Javascript流程控制语句学习笔记
2015/11/29 Javascript
Windows环境下npm install 报错: operation not permitted, rename的解决方法
2016/09/26 Javascript
微信JS SDK接入的几点注意事项(必看篇)
2017/06/23 Javascript
JavaScript实现QQ列表展开收缩扩展功能
2017/10/30 Javascript
Angular实现svg和png图片下载实现
2019/05/05 Javascript
JavaScript实现图片轮播特效
2019/10/23 Javascript
JavaScript获取当前url路径过程解析
2019/12/27 Javascript
[01:14:10]2014 DOTA2国际邀请赛中国区预选赛 SPD-GAMING VS Orenda
2014/05/22 DOTA
linux系统使用python监测系统负载脚本分享
2014/01/15 Python
Python简单生成8位随机密码的方法
2017/05/24 Python
Python之Scrapy爬虫框架安装及使用详解
2017/11/16 Python
Flask框架模板继承实现方法分析
2019/07/31 Python
Numpy实现卷积神经网络(CNN)的示例
2020/10/09 Python
使用CSS3实现input多选框自定义样式的方法示例
2019/07/19 HTML / CSS
欧洲最大的婴幼儿服装及内衣公司:Petit Bateau(小帆船)
2016/08/16 全球购物
中国综合性网上购物商城:当当(网上卖书起家)
2016/11/16 全球购物
英国时尚饰品和发饰购物网站:Claire’s
2017/07/04 全球购物
加拿大在线隐形眼镜和眼镜店:VisionPros
2019/10/06 全球购物
德国户外装备、登山运动和攀岩商店:tapir store
2020/02/12 全球购物
大班亲子运动会方案
2014/06/10 职场文书
激励员工的口号
2014/06/16 职场文书
群众路线教育实践活动调研报告
2014/11/03 职场文书
团代会闭幕词
2015/01/28 职场文书
小学教师党员承诺书
2015/04/27 职场文书
幼儿园教师心得体会范文
2016/01/21 职场文书