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高级程序设计 DOM学习笔记
Sep 10 Javascript
jquery.map()方法的使用详解
Jul 09 Javascript
网页前端登录js按Enter回车键实现登陆的两种方法
May 10 Javascript
理解AngularJs篇:30分钟快速掌握AngularJs
Dec 23 Javascript
原生js实现手风琴功能(支持横纵向调用)
Jan 13 Javascript
从零学习node.js之express入门(六)
Feb 25 Javascript
深入剖析Express cookie-parser中间件实现示例
Feb 01 Javascript
element ui table(表格)实现点击一行展开功能
Dec 04 Javascript
前端路由&amp;webpack基础配置详解
Jun 10 Javascript
在layui中对table中的数据进行判断(0、1)转换为提示信息的方法
Sep 28 Javascript
微信小程序仿抖音短视频切换效果的实例代码
Jun 24 Javascript
vue.js 输入框输入值自动过滤特殊字符替换中问标点操作
Aug 31 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
smarty实例教程
2006/11/19 PHP
php读取30天之内的根据算法排序的代码
2008/04/06 PHP
PHP 年龄计算函数(精确到天)
2012/06/07 PHP
PHP实现扎金花游戏之大小比赛的方法
2015/03/10 PHP
PHP 使用 Imagick 裁切/生成缩略图/添加水印自动检测和处理 GIF
2016/02/19 PHP
php封装的page分页类完整实例
2016/10/18 PHP
THINKPHP-Apache服务器中使用Alias虚拟目录URL重写 隐藏index.php
2021/03/09 PHP
JQUERY实现网页右下角固定位置展开关闭特效的方法
2015/07/27 Javascript
JQueryEasyUI之DataGrid数据显示
2016/11/23 Javascript
angularjs使用directive实现分页组件的示例
2017/02/07 Javascript
移动端触摸滑动插件swiper使用方法详解
2017/08/11 Javascript
two.js之实现动画效果示例
2017/11/06 Javascript
nodejs中用npm初始化来创建package.json的实例讲解
2018/10/10 NodeJs
axios使用拦截器统一处理所有的http请求的方法
2018/11/02 Javascript
layui switch 开关监听 弹出确定状态转换的例子
2019/09/21 Javascript
在 Vue 中使用 JSX 及使用它的原因浅析
2020/02/10 Javascript
js实现带箭头的进度流程
2020/03/26 Javascript
[05:36]DOTA2 2015国际邀请赛中国区预选赛第四日TOP10
2015/05/29 DOTA
在Python的Django框架中编写错误提示页面
2015/07/22 Python
解决python 输出是省略号的问题
2018/04/19 Python
python 用lambda函数替换for循环的方法
2018/06/09 Python
pytorch 修改预训练model实例
2020/01/18 Python
Python pytesseract验证码识别库用法解析
2020/06/29 Python
Python3中小括号()、中括号[]、花括号{}的区别详解
2020/11/15 Python
Python中生成ndarray实例讲解
2021/02/22 Python
python 如何用urllib与服务端交互(发送和接收数据)
2021/03/04 Python
eDreams巴西:廉价机票,酒店优惠和度假套餐
2017/04/14 全球购物
linux面试题参考答案(6)
2016/06/23 面试题
大学自我评价
2014/02/12 职场文书
大学竞选班长演讲稿
2014/04/24 职场文书
2015届大学生就业推荐表自我评价
2014/09/27 职场文书
沂蒙六姐妹观后感
2015/06/08 职场文书
2015年四年级班主任工作总结
2015/10/22 职场文书
新手,如何业余时间安排好写作、提高写作能力?
2019/10/21 职场文书
vue backtop组件的实现完整代码
2021/04/07 Vue.js
pycharm debug 断点调试心得分享
2021/04/16 Python