概述
在开篇之前,先附上日历的代码地址和演示地址,代码是本文要分析的代码,演示效果是本文要实现的效果
代码地址:https://github.com/aspwebchh/javascript-control/tree/master/calendar
演示地址: https://www.chhblog.com/html/demo/calendar.html
本文的目的除了详细说明开发一款具备基本功能的网页日历的方法与细节以外,还附加说明了如何合理的组织日历特效的代码和因此带来的好处。
按照本文的教程开发出来的效果如下

他具有选择年月日、选择今天、清空文本框这些日历的基本功能,能满足日常项目中出现的普通日期选择需求, 算的上是五脏俱全的小麻雀。
本文主要描述JavaScript实现的细节,日历的CSS布局细节将被省略,有兴趣的同学可阅读calendar.css中的css代码获知实现方法。
此日历特效由原生JavaScript代码写成,并不依赖jQuery等第三方框架。它的JavaScript代码由三个文件构成
common.js
公用函数库文件, 里面的函数都是通用型的,并不仅仅和特效相关,在任何网页特效中都可以使用它们
calendar_core.js
一个纯粹的、通用的日历特效的所有代码,更任何其它页面元素没有关系,比如说用来放置日期的文本框
calendar.js
合理调用calendar_core.js中的代码来构建一个真正可以使用的日历特效。
关于calendar_core.js和calendar.js的说明,似乎有点令人犯迷糊,不过这不要紧,通过下面的详细讲解,会使读者了解到这两个文件中代码作用与区别。
代码规约
因为JavaScript在一些常规的编程概念上没有统一的实现方法的缘故,在介绍日历的核心实现逻辑之情,先介绍下代码中所有使用的容易分散读者注意力或者造成读者出现理解偏差的语法细节。
防止全局变量污染名称空间
此案列的大部分代码会被这样一段代码包围起来
(function(){ //功能代码 })();其实这么做的主要目的是为了让变量名称和函数的名称全局名称空间, 换句话说就是让用不到它的地方看不到它。
那为什么这个function要被一个括号括起来,而且在这个括号后面再加上一个括号。 括号的作用很简单,跟小学数学中所学的括号作用一样,是用来提升运算优先级的,比如说(1+2)*3,其中(1+2)会被优先与乘法运算,返回的结果就是3。可JavaScript没有规定,括号中必须放置四则运算表达式,括号中也可以放别的东西,比如说函数。这么一说就好理解了
(function(){ //功能代码 })();这段代码可一被分解为两步, 第一个括号的作用是返回括号中的函数,第二个括号的作用是调用第一个括号返回的函数,这跟下面这段代码是一个意思,只是合在一起可以省略函数名。
var func = (function(){ //功能代码 }); func();类的实现
非ES6的JavaScript语法不支持类,但是类是不可缺少的编程元素,所幸JavaScript可以通过function关键字模拟类的实现。
常规的模拟方法是使用function和function的它的prototype属性,可这么做无法实现面向对象中private关键字的效果,所以我在这个案列中并没有采用这种方法,而是使用了
function Klass(){ this.publicFunc1 = function(){} this.publicFunc2= funciton(){} var privateFunc1 = funciton(){} var privateFunc2 = function(){} } var klass = new Klass(); Klass.publicFunc1(); Klass.publicFunc2();这种方式模拟类的实现。
实现细节
公用函数库 - common.js
此文件中有4个函数
addEventHandler
为DOM对象绑定事件。因为要兼容低版本IE,所以特地封装成函数
removeEventHandler
移除DOM对象绑定的事件
getOffset
获得html元素在页面中的位置。使用场景如点击输入框弹出日历时将日历定位到文本框下方就要用到这个函数。
checkDate
检查日期字符串格式是否合法
这4个函数的代码在文中略去,有需要的读者可直接查看源代码
日历核心类 - calendar_core.js
此文件包含日历特效的核心功能,其中有一个函数和一个类。
函数 newCalendarID
函数代码如下
var instanceCount = 0; function newCalendarID(){ return 'calender_' + ( ++instanceCount ); }这个函数的作用是生成代表日历DOM元素的ID。 很多时候, 一个页面上不会只有一个日历,如下图

所以必须要一个不重复的值作为不同日历HTML元素的ID,以防止JavaScript操作日历html元素时造成冲突。 newCalendarID通过自增一个数值变量并结合一个字符串来生成日历的ID,生成的ID格式如下
calender_1
calender_2
calender_3
calender_4
这个函数在日历的构造函数中被调用,每次实例化一个日历时为日历html元素赋予一个ID。
类 Calender
类 Calender 封装了实现日历功能的代码,包括生成日历、年份月份切换、 选择清空日期等等。
Calender 类的公共接口如下
function Calender() { //事件 this.onClear =
