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 相关文章推荐
多浏览器兼容的获取元素和鼠标的位置的js代码
Dec 15 Javascript
JavaScript 编写匿名函数的几种方法
Feb 21 Javascript
js confirm()方法的使用方法实例
Jul 13 Javascript
jQuery学习笔记之jQuery动画效果
Sep 09 Javascript
JavaScript优化专题之Loading and Execution加载和运行
Jan 20 Javascript
使用JavaScript为Kindeditor自定义按钮增加Audio标签
Mar 18 Javascript
解读Bootstrap v4 sass设计
May 29 Javascript
详解Angular中$cacheFactory缓存的使用
Aug 19 Javascript
jquery插件bootstrapValidator数据验证详解
Nov 09 Javascript
javascript常用经典算法详解
Jan 11 Javascript
js匿名函数使用&amp;传参(实例)
Sep 08 Javascript
浅谈Node框架接入ELK实践总结
Feb 22 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防注入代码
2010/04/07 PHP
php ci框架中加载css和js文件失败的解决方法
2014/03/03 PHP
Yii控制器中操作视图js的方法
2016/07/04 PHP
TopList标签和JavaScript结合两例
2007/08/12 Javascript
JS实现仿Windows经典风格的选项卡Tab切换代码
2015/10/20 Javascript
一些实用性较高的js方法
2016/04/19 Javascript
详解JavaScript常量定义
2017/01/03 Javascript
jQuery UI仿淘宝搜索下拉列表功能
2017/01/10 Javascript
xmlplus组件设计系列之下拉刷新(PullRefresh)(6)
2017/05/03 Javascript
Node.js实现连接mysql数据库功能示例
2017/09/15 Javascript
原生JS实现获取及修改CSS样式的方法
2018/09/04 Javascript
微信小程序中this.data与this.setData的区别详解
2018/09/17 Javascript
教你如何编写Vue.js的单元测试的方法
2018/10/17 Javascript
微信小程序之swiper滑动面板用法示例
2018/12/04 Javascript
使用 node.js 模仿 Apache 小部分功能
2019/07/07 Javascript
vue 使用lodash实现对象数组深拷贝操作
2020/09/10 Javascript
vue-amap根据地址回显地图并mark的操作
2020/11/03 Javascript
[02:08:58]2014 DOTA2国际邀请赛中国区预选赛 Ne VS CIS
2014/05/22 DOTA
python正则表达式去掉数字中的逗号(python正则匹配逗号)
2013/12/25 Python
python basemap 画出经纬度并标定的实例
2019/07/09 Python
Python 在OpenCV里实现仿射变换—坐标变换效果
2019/08/30 Python
python实现的Iou与Giou代码
2020/01/18 Python
TensorFlow 输出checkpoint 中的变量名与变量值方式
2020/02/11 Python
Python接口测试文件上传实例解析
2020/05/22 Python
Python DES加密实现原理及实例解析
2020/07/17 Python
Python中random模块常用方法的使用教程
2020/10/04 Python
Jupyter Notebook添加代码自动补全功能的实现
2021/01/07 Python
HTML5 贪吃蛇游戏实现思路及源代码
2013/09/03 HTML / CSS
HTML5实现简单图片上传所遇到的问题及解决办法
2016/01/20 HTML / CSS
贝玲妃美国官方网站:Benefit美国
2016/08/28 全球购物
购买中国最好的电子产品:Geekbuying
2018/03/13 全球购物
Myprotein台湾官方网站:全球领先的运动营养品牌
2018/12/10 全球购物
饿了么订餐官网:外卖、网上订餐
2019/06/28 全球购物
买卖车协议书
2014/04/21 职场文书
2015年信访工作总结
2015/04/07 职场文书
高中班主任培训心得体会
2016/01/07 职场文书