js日历控件

核心思路参考了群里的MK桑的,在此谢过。

(function(){
	var db = document.body;
	var Calendar = function(opts){
		return new Calendar.prototype.init(opts);
	};
	Calendar.prototype = {
		constructor:Calendar,
		init:function(opts){
			this.opts = extend({
				target:'',
				initial:'2012/09/27',
				format:'YYYY-MM-DD',
				callback:function(){}
			},opts||{});
			var _this = this;
			this.target = $(this.opts.target);
			addEvent(this.target,'click',function(){_this.create();});
		},
		create:function(){
			var de = this.target.getAttribute('data-date');
			this.defaultValue = this.defaultValue || (de && new Date(de)) || (this.initial ? new Date(this.initial) : new Date());
			var year = this.defaultValue.getFullYear(),month = this.defaultValue.getMonth(),date =this.defaultValue.getDate(), _this = this;
			var days = this.calculateDays(year,month),fragment = document.createDocumentFragment(),ul = document.createElement('ul');
			this.close();
			this.wrapper = createEl('<div id="date_wrapper"><div id="date_header"><div id="yearBox"><span id="prevYear">«</span><em>'+year+'</em><span id="nextYear">»</span></div><div id="monthBox"><span id="prevMonth">«</span><em>'+(month+1)+'</em><span id="nextMonth">»</span></div></div><div id="date_weekBox"><ul><li>日</li><li>一</li><li>二</li><li>三</li><li>四</li><li>五</li><li>六</li></ul></div><div id="date_dateBox"></div></div>',db);
			
			for(var i=0,len=days.length;i<len;i++){
				var li = document.createElement('li');
				var y = days[i].getFullYear(),m = days[i].getMonth(),d = days[i].getDate();
				var f = m == month;
				var fl = year == y && month == m && date == d;
				li.setAttribute('data-date',days[i]);
				li.innerHTML = d;
				addClass(li,f ? 'black' : 'gray');
				fl && addClass(li,'current');
				fragment.appendChild(li);
			}
			ul.appendChild(fragment);
			$('date_dateBox').appendChild(ul);
			
			setPosition(this.wrapper,this.target);
			
			addEvent($('prevYear'),'click',function(){
				_this.defaultValue.setMonth(_this.defaultValue.getMonth()-12,date);
				_this.create();
			});
			addEvent($('nextYear'),'click',function(){
				_this.defaultValue.setMonth(_this.defaultValue.getMonth()+12,date);
				_this.create();
			});
			addEvent($('prevMonth'),'click',function(){
				_this.defaultValue.setMonth(_this.defaultValue.getMonth()-1,date);
				_this.create();
			});
			addEvent($('nextMonth'),'click',function(){
				_this.defaultValue.setMonth(_this.defaultValue.getMonth()+1,date);
				_this.create();
			});
			addEvent(ul,'click',function(e){
				e = e || window.event;
				var target = e.target || e.srcElement;
				if(hasClass(target,'black')){
					var date = target.getAttribute('data-date');
					_this.target.setAttribute('data-date',date);
					_this.defaultValue = new Date(date);
					if(_this.target.type == 'text') _this.target.value = formatDate(date,_this.opts.format);
					_this.opts.callback && _this.opts.callback(date);
					_this.close();
				};
			});			
		},
		set:function(d){
			this.defaultValue = d ? new Date(d) : new Date();
			this.create();
		},
		get:function(){
			return this.defaultValue;
		},
		close:function(){
			if(!this.wrapper) return;
			this.wrapper.parentNode.removeChild(this.wrapper);
			this.wrapper = null;
		},
		trigger:function(){
			this.create();
		},
		calculateDays:function(y,m){
			var offset, dFirstDay = new Date(y, m, 1), dLastDay = new Date(y, m + 1, 0), arr = [];
			dFirstDay.setMonth(m, 1 - dFirstDay.getDay());
			dLastDay.setMonth(m, dLastDay.getDate() + 6 - dLastDay.getDay());
			offset = parseInt((dLastDay - dFirstDay) / (1000*60*60*24)) + 1;
			var _y = dFirstDay.getFullYear(), _m = dFirstDay.getMonth(), _d = dFirstDay.getDate();
			for(var i=0; i<offset; i++){
				var d = new Date(_y, _m, _d + i);
				arr.push(d);
			}
			return arr;
		}
	};
	Calendar.prototype.init.prototype = Calendar.prototype;
	window.Calendar = Calendar;
	
	
	function $(id){
		return typeof id == 'string' ? document.getElementById(id) : id;
	};
	function createEl(str,parent){
		var div = document.createElement('div'),el;
		div.innerHTML = str;
		el = div.firstChild;
		parent && parent.appendChild(el);
		return el;
	};
	function extend(t,s){
		for(var i in s ) t[i] = s[i];
		return t;
	};
	function getElementPos(el){
		var x = 0,y=0;
		if(el.getBoundingClientRect){
			var pos = el.getBoundingClientRect();
			var d_root = document.documentElement,db = document.body;
			x = pos.left + Math.max(d_root.scrollLeft,db.scrollLeft) - d_root.clientLeft;
			y = pos.top + Math.max(d_root.scrollTop,db.scrollTop) - d_root.clientTop;
		}else{
			while(el != db){
				x += el.offsetLeft;
				y += el.offsetTop;
				el = el.offsetParent;
			};
		};
		return {
			x:x,
			y:y
		};
	};
	function setPosition(target,reference){
		var pos = getElementPos(reference);
		var left = pos.x,top = pos.y;
		var width = reference.offsetWidth,height = reference.offsetHeight;
		var w = target.offsetWidth,h = target.offsetHeight;
		var st = Math.max(document.documentElement.scrollTop,document.body.scrollTop),sl = Math.max(document.documentElement.scrollLeft,document.body.scrollLeft);
		var cw =  document.documentElement.clientWidth,ch = document.documentElement.clientHeight;
		if(ch+st-top-height-1 > h ){
			target.style.top = top + height + 1 + 'px';
		}else{
			target.style.top = top - h - 1 + 'px';
		};
		if(cw+sl-left-width > w){
			target.style.left = left + 'px';
		}else{
			target.style.left = left + width - w + 'px';
		};
	};
	function addEvent(el,type,fn){
		if(typeof el.addEventListener != 'undefined'){
			el.addEventListener(type,fn,false);
		}else if(typeof el.attachEvent != 'undefined'){
			el.attachEvent('on'+type,fn);
		}else{
			el['on'+type] = fn;
		};
	};
	function formatDate(t,tpl){
		var strs=[], w, keys, year, val,t= t ? new Date(t) : new Date();
		w = 'FullYear,Month,Date'.split(',');
		keys = [/YYYY/g, /YY/g, /MM/g, /M/g, /DD/g, /D/g];
		for (var i = 0; i < 3; i++) {
			val = t['get' + w[i]]() + (w[i] === 'Month' ? 1 : 0);
			strs.push(('0' + val).slice( - 2), val)
		};
		year = [strs[1], strs[0]].concat(strs.slice(2));
		for (var i = 0; i < 6; i++) {
			tpl = tpl.replace(keys[i], year[i])
		};
		return tpl;
	};
	function clear(str){
		return str.replace(/^\s+|\s+$/g,'').replace(/\s+/,' ');
	};
	function hasClass(el,oClass){
		return (' '+el.className+' ').indexOf(' '+oClass+' ') > -1;
	};
	function addClass(el,oClass){
		if(hasClass(el,oClass)) return;
		var c = el.className;
		el.className = clear(c? c + ' '+oClass : oClass);
	};
	function removeClass(el,oClass){
		if(!hasClass(el,oClass)) return;
		var c = el.className;
		el.className = clear((' '+c+' ').replace(' '+oClass+' ',''));
	};
})();

HTML:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<title></title>
	<style type="text/css">
		* {padding:0;margin:0;}
		body { font-family:Arial, Helvetica, sans-serif; font-size:12px;}
		ul { list-style:none;}
		#date_wrapper { width:287px; position:absolute; overflow:hidden; background:#fff;}
		#date_header {height:35px;overflow:hidden;}
		#date_header span {display:inline-block;*display:inline;*zoom:1; width:20px;height:20px;line-height:20px;text-align:center;margin:0 5px;vertical-align: 2px; cursor:pointer;font-size:15px;font-weight:bold; color:#fff;}
		#date_header em {font-style: normal; font-weight;bold; font-size:18px; color:#fff;}
		#yearBox { background:#254b7c;float:left;width:204px;height:35px; line-height:35px; text-align:center;}
		#monthBox { background:#436ca5;float:left;width:82px;height:35px; line-height:35px; text-align:center;}
		#date_weekBox li { display:inline-block;*display:inline;*zoom:1;  width:40px; height:30px; margin-right:1px; line-height:30px; text-align:center; background:#c2d7ec; color:#254b7c;}
		#date_dateBox li { display:inline-block;*display:inline;*zoom:1;  width:40px; height:40px; line-height:40px; text-align:center; background:#eaf3fa;margin-right:1px; margin-bottom:1px; font-size:15px; cursor:pointer; color:#254b7c;}
		#date_dateBox li.gray { color:#a6c0d7;}
		#date_dateBox li.current { background:#254b7c; color:#fff;font-weight:bold; }
		input[type="button"] { padding:3px 10px;}
		#calendar {position:absolute;top:400px;left:500px;width:274px;height:30px;line-height:30px;padding:0 5px;border:1px solid #C2D7EC; color:#254b7c;}
	</style>
</head>
<body>
	<input type="text" id="calendar"/>
	<input type="button" id="trigger" value=" trigger" />
	<input type="button" id="set" value="set" />
	<input type="button" id="get" value="get" />
	<input type="button" id="close" value="close" />
	<div style="height:1500px;"></div>
	<script type="text/javascript" src="calendar.js"></script>
	<script type="text/javascript">
		var trigger = document.getElementById('trigger');
		var set = document.getElementById('set');
		var get = document.getElementById('get');
		var close = document.getElementById('close');
		var a = Calendar({
			target:'calendar'
		});
		trigger.onclick = function(){
			a.trigger();
		};
		set.onclick = function(){
			a.set();
			a.trigger();
		};
		get.onclick = function(){
			alert(a.get());
		};
		close.onclick = function(){
			a.close();
		}
	</script>
</body>
</html>

测试时可以将input定义到浏览器的四个角上试下

posted @ 2013-02-22 13:35  zjhsd2007  阅读(4398)  评论(3编辑  收藏  举报