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显示隐藏层比较不错的方法分析
Sep 30 Javascript
让IE6支持min-width和max-width的方法
Jun 25 Javascript
js中top/parent/frame概述及案例应用
Feb 06 Javascript
JavaScript中如何通过arguments对象实现对象的重载
May 12 Javascript
JSON取值前判断
Dec 23 Javascript
Jquery插件实现点击获取验证码后60秒内禁止重新获取
Mar 13 Javascript
基于jQuery实现照片墙自动播放特效
Jan 12 Javascript
Vue实现动态响应数据变化
Apr 28 Javascript
bootstrap table单元格新增行并编辑
May 19 Javascript
vue实现全选和反选功能
Aug 31 Javascript
微信小程序实现一张或多张图片上传(云开发)
Sep 25 Javascript
vue使用echarts图表自适应的几种解决方案
Dec 04 Vue.js
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之规范编程命名小结
2013/05/15 PHP
PHP eval函数使用介绍
2013/12/08 PHP
PHP中copy on write写时复制机制介绍
2014/05/13 PHP
PHP批量去除BOM头内容信息代码
2016/03/11 PHP
thinkPHP框架实现多表查询的方法
2018/06/14 PHP
PHP实现获取ip地址的5种方法,以及插入用户登录日志操作示例
2019/02/28 PHP
php pdo连接数据库操作示例
2019/11/18 PHP
体验js中splice()的强大(插入、删除或替换数组的元素)
2013/01/16 Javascript
jquery遍历数组与筛选数组的方法
2013/11/05 Javascript
浅析Js中的单引号与双引号问题
2013/11/06 Javascript
JavaScript调用客户端的可执行文件(示例代码)
2013/11/28 Javascript
使用jQuery实现图片遮罩半透明坠落遮挡
2015/03/16 Javascript
WEB前端开发框架Bootstrap3 VS Foundation5
2016/05/16 Javascript
JS对象创建的几种方式整理
2017/02/28 Javascript
javascript高仿热血传奇游戏实现代码
2018/02/22 Javascript
Vue实现自定义下拉菜单功能
2018/07/16 Javascript
基于vue如何发布一个npm包的方法步骤
2019/05/15 Javascript
详解iview的checkbox多选框全选时校验问题
2019/06/10 Javascript
详解Angular Karma测试的持续集成实践
2019/11/15 Javascript
Vue.js仿Select下拉框效果
2020/02/18 Javascript
Python深入学习之特殊方法与多范式
2014/08/31 Python
Python常用知识点汇总
2016/05/08 Python
Python批量发送post请求的实现代码
2018/05/05 Python
解决pandas 作图无法显示中文的问题
2018/05/24 Python
Python一键查找iOS项目中未使用的图片、音频、视频资源
2019/08/12 Python
python递归函数求n的阶乘,优缺点及递归次数设置方式
2020/04/02 Python
基于SpringBoot构造器注入循环依赖及解决方式
2020/04/26 Python
Python如何操作docker redis过程解析
2020/08/10 Python
css3动画过渡实现鼠标跟随导航效果
2018/02/08 HTML / CSS
CSS3按钮鼠标悬浮实现光圈效果源码
2016/09/11 HTML / CSS
澳大利亚领先的女帽及配饰公司:Morgan&Taylor
2019/12/01 全球购物
经典优秀个人求职自荐信格式
2013/09/25 职场文书
文明上网主题班会
2015/08/14 职场文书
团组织关系介绍信
2019/06/24 职场文书
Pytorch实现图像识别之数字识别(附详细注释)
2021/05/11 Python
Java 在生活中的 10 大应用
2021/11/02 Java/Android