起因
需要实现一个日历功能,网上找了几个示例,都是根据各种库和插件,居然没有纯净的 js 完成的日历插件,不免有些诧异,正好有时间,准备通过 js 编写一个简单的日历 demo 基础,可自由根据使用的插件进行显示层的定制。
效果图
前提
算法
说一下日历的算法
- (本月第一天的星期数 + 本月的天数)/7 可以知道本月需要占据几行。
- 将日历看为二维数组,第一级遍历条件为本月行数,第二级为 0~7(直观形象为一个日历 table,自左向右,自上而下循环)。
- n 为 0~7 循环参数, 计算当前日历方格显示数值为当前日期: 行数*7 + n - 本月第一天 + 1。
- 二月的天数根据闰年会有不同,闰年的计算方式: 当前年份能被 400 整除,或者当前的年份能被 4 整除且不能被 100 整除。
Date
日历功能实现必须通过 js 的 Date 对象提供的基础数值。介绍一下用到的方法功能
new Date().getFullYear(); //当前年份 2015 new Date().getMonth(); //当前月份 0~11 new Date().getDate(); //当前月中的某一天 1~31 new Date().getDay(); //一周中的某一天 0~6 new Date(year, month, day); //根据构造函数返回Date对象
实现
这里写出来编写代码思路分析的过程,可以跳过直接看下方的完整代码。
先抽象出二维数组模型,7 列已经确定,需要先根据算法 1 算出本月的日历行数,但是二月的天数不一致,所以先要根据是否为闰年算出二月的天数。
var calendar = { isLeap: function(vYear) { return vYear % 400 == 0 || (vYear % 4 == 0 && vYear % 100 != 0); }, getFebruaryDays: function(vYear) { return this.isLeap(vYear) ? 29 : 28; } }
本月第一天的星期数可以根据 new Date(currentYear, currentMonth, 1).getDay()得出。
monthFirstDay 为本月第一天的星期数,monthDays 为 12 月的天数组成的数组。根据构造函数计算赋值,并返回 this 对象方便链式调用。
var calendar = { year: null, month: null, date: null, day: null, monthDays: null, monthFirstDay: null, ctor: function(vNow) { var now = vNow || new Date(); //如果为指定date对象,则为当前日期对象 this.year = now.getFullYear(); this.month = now.getMonth(); this.date = now.getDate(); this.day = now.getDay(); this.monthFirstDay = new Date(this.year, this.month, 1).getDay(); this.monthDays = [ 31, this.getFebruaryDays(this.year), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; return this; }, isLeap: function(vYear) { return vYear % 400 == 0 || (vYear % 4 == 0 && vYear % 100 != 0); }, getFebruaryDays: function(vYear) { return this.isLeap(vYear) ? 29 : 28; } }
计算日历行数
getMonthDay: function() { return this.monthDays[this.month]; }, getCalTr: function() { return (this.monthFirstDay + this.getMonthDay()) / 7; },
循环二维数组得到日历, *console.log(n);*可结合使用的框架进行输出展示。
cal: function() { var that = this; for (var i = 0; i < this.getCalTr(); i++) { for (var j = 0; j < 7; j++) { var n = (i * 7 + j) - that.monthFirstDay + 1; if (n > 0 && n <= that.getMonthDay()) { console.log(n); } } } }
完整代码,在控制台查看输出的日历
var calendar = { year: null, month: null, date: null, day: null, monthDays: null, monthFirstDay: null, days: [ "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日" ], ctor: function(vNow) { var now = vNow || new Date(); //如果为指定date对象,则为当前日期对象 this.year = now.getFullYear(); this.month = now.getMonth(); this.date = now.getDate(); this.day = now.getDay(); this.monthFirstDay = new Date(this.year, this.month, 1).getDay(); this.monthDays = [ 31, this.getFebruaryDays(this.year), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; return this; }, isLeap: function(vYear) { return vYear % 400 == 0 || (vYear % 4 == 0 && vYear % 100 != 0); }, getFebruaryDays: function(vYear) { return this.isLeap(vYear) ? 29 : 28; }, format: function() { return (this.month + 1) + "/" + this.date + "/" + this.year + " " + this.dayMap[this.day]; }, getDay: function() { return this.days[this.day - 1] }, getMonthDay: function() { return this.monthDays[this.month]; }, getCalTr: function() { return (this.monthFirstDay + this.getMonthDay()) / 7; }, cal: function() { var that = this; console.log("%c 日 一 二 三 四 五 六 ",'background: #222; color: #bada55'); console.log("-----------------------------------"); for (var i = 0; i < this.getCalTr(); i++) { var temp = ""; for (var j = 0; j < 7; j++) { var tempData = (i * 7 + j) - that.monthFirstDay + 1 if (tempData < 1) { temp = temp + "prev "; } else if (tempData > that.getMonthDay()) { temp = temp + " next"; } else { if (tempData > 9) { temp = temp + " " + tempData + " "; } else { temp = temp + " " + tempData + " "; } } } console.log(temp); console.log("-----------------------------------"); } } } calendar.ctor().cal(); calendar.ctor(new Date(2015, 10)).cal();
总结
不足
本例中的 ctor 并非构造函数,而是针对一个对象进行变更,重新执行 ctor 后会替换 calendar 的属性值。
未对之前和之后的日期进行获取,如需相关功能,可在 ctor 中设置 prevMonth 和 nextMonth 的值,需要注意跨年度问题,时间和需求问题,暂未实现。
思考
是否采用构造函数的方式生成多个对象? (如果是工具类的话,不需要构造函数)
方法中采用 this.param 还是获取外部参数 如何界定?
收获
用面向对象的方式编写 js,思路清晰,语感更好。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于