最近项目因需要一个个性化的日历,用react写了一个日历控件,如图所示
(function(global){
flag = 0;
var choice;
var Calendar = function(div, date, datemoney){
this.div = document.getElementById(div);
var w = document.documentElement.clientWidth;
var h = document.documentElement.clientHeight;
this.width = w;
this.height = h*3/5;
this.date = date;
this.div.style.width = this.width + 'px'; //按默认值设置回去
this.div.style.height = this.height + 'px';//按默认值设置回去
this.datemoney = datemoney;
document.getElementById('header_date').innerHTML = this.date.getFullYear() + '年' + (this.date.getMonth() + 1) + '月';
};
Calendar.prototype['showUI'] = function(){
var exist = document.getElementById('day_table');
for(var i = 0; i < 42; i++){
var aim = document.getElementById('day'+i);
if (aim!=null && 1 == aim.getAttribute('flag'))
choice = aim.getAttribute('date');
}
//alert(choice);
if(!!exist){
this.div.removeChild(exist);
}
var width = this.width,
height = this.height,
cell = {width: width/7, height: (height -30 - 20)/6},
monthArr = this._monthPanel(this.date);
this.div.style.cursor = 'default';
this.div.style.fontFamily = '微软雅黑';
var CurDate = new Date();
var month = CurDate.getMonth()+1;
var day = CurDate.getDate();
var today;
if(month>=10 && day >=10)
today = CurDate.getFullYear()+"/"+month+"/"+day;
else if(month>=10 && day <10)
today = CurDate.getFullYear()+"/"+month+"/0"+day;
else if(month<10 && day >= 10)
today = CurDate.getFullYear()+"/0"+month+"/"+day;
else
today = CurDate.getFullYear()+"/0"+month+"/0"+day;
var tableDOM = document.createElement('table');
tableDOM.id = "day_table";
//生成日历表格框架,通过monthArr向其中复制
for(var i=0;i<42;i++){
var attr_date;
var attr_month = monthArr.date[i].getMonth()+1;
var attr_day = monthArr.date[i].getDate();
if(attr_month>=10 && attr_day >=10)
attr_date = monthArr.date[i].getFullYear()+"/"+attr_month+"/"+attr_day;
else if(attr_month>=10 && attr_day <10)
attr_date = monthArr.date[i].getFullYear()+"/"+attr_month+"/0"+attr_day;
else if(attr_month<10 && attr_day >= 10)
attr_date = monthArr.date[i].getFullYear()+"/0"+attr_month+"/"+attr_day;
else
attr_date = monthArr.date[i].getFullYear()+"/0"+attr_month+"/0"+attr_day;
if (i%7 == 0){
var trDOM = document.createElement('tr');
trDOM.id = "week"+parseInt(i/7);
var tdDOM = document.createElement('td');
var cellDOM = document.createElement('div');
cellDOM.style.width = cell.width + 'px';
cellDOM.style.height = cell.height + 'px';
cellDOM.setAttribute('flag',"0");
cellDOM.setAttribute('date',attr_date);
var pDOM = document.createElement('p');
if(cellDOM.getAttribute('date') == today){
pDOM.innerHTML = monthArr.date[i].getDate()+"今日";
pDOM.id = "now";
}else
pDOM.innerHTML = monthArr.date[i].getDate();
pDOM.style.marginTop = parseInt(cell.width/7)+'px';
//pDOM.style.marginBottom = '0';
cellDOM.appendChild(pDOM);
cellDOM.className = 'day';
cellDOM.id = 'day' + i;
tdDOM.appendChild(cellDOM);
trDOM.appendChild(tdDOM);
tableDOM.appendChild(trDOM);
}
else{
var tdDOM = document.createElement('td');
var cellDOM = document.createElement('div');
cellDOM.style.width = cell.width + 'px';
cellDOM.style.height = cell.height + 'px';
cellDOM.setAttribute('flag',"0");
cellDOM.setAttribute('date',attr_date);
//cellDOM.setAttribute('disabled','disabled');
var pDOM = document.createElement('p');
if(cellDOM.getAttribute('date') == today){
pDOM.innerHTML = monthArr.date[i].getDate()+"今日";
pDOM.id = "now";
}else
pDOM.innerHTML = monthArr.date[i].getDate();
pDOM.style.marginTop = parseInt(cell.width/7)+'px';
//pDOM.style.marginBottom = '0';
cellDOM.appendChild(pDOM);
cellDOM.className = 'day';
cellDOM.id = 'day' + i;
tdDOM.appendChild(cellDOM);
trDOM.appendChild(tdDOM);
}
if(i < monthArr.preLen || i >= monthArr.currentLen + monthArr.preLen){
cellDOM.style.color = '#BFBFBF';
}
}
this.div.appendChild(tableDOM);
var date;
//判断从外部传入的数组,加入日期对应的钱数
for(var i = 0; i < 42; i++){
var aim = document.getElementById('day'+i);
//alert(this.datemoney);
for(date in this.datemoney){
if(aim!=null&&aim.getAttribute("date")==date && date>=today)
{
//test.style.backgroundColor = "#fedd00";
aim.setAttribute("money",this.datemoney[date]);
aim.className = "day hasmoney";
var money = document.createElement('p');
money.className = "money";
money.innerHTML = "¥"+this.datemoney[date];
aim.appendChild(money);
//choice.style.border = "2px solid #fedd00";
if(choice==aim.getAttribute('date')){
aim.style.border = "2px solid #fedd00";
aim.setAttribute('flag','1');
}
}
}
}
//点击日期生成票的张数和总钱数
$(".hasmoney").on("click",function(e){
var node = e.target;
if(node.id.indexOf('day') > -1 && node.className.indexOf('hasmoney') > -1){
//callback(node.getAttribute('date'));
if(1==node.getAttribute("flag") && flag == 1){
node.setAttribute('flag',"0");
node.style.border = "1px solid #C8CACC";
document.getElementById('number').innerHTML = 0;
flag = 0;
document.getElementById('total-money').innerHTML = 0;
}
else if(0==node.getAttribute("flag")&& flag == 0){
node.setAttribute('flag',"1");
flag = 1;
node.style.border = "2px solid #fedd00";
document.getElementById('number').innerHTML = 1;
document.getElementById('total-money').innerHTML = node.getAttribute('money');
}
if(0 == flag){
document.getElementById('number').innerHTML = 0;
document.getElementById('total-money').innerHTML = 0;
}
}
});
$(".money").on("click",function(e){
var node = e.target.parentNode;
if(node.id.indexOf('day') > -1 && node.className.indexOf('hasmoney') > -1){
//callback(node.getAttribute('date'));
if(1==node.getAttribute("flag") && flag == 1){
node.setAttribute('flag',"0");
node.style.border = "1px solid #C8CACC";
document.getElementById('number').innerHTML = 0;
flag = 0;
document.getElementById('total-money').innerHTML = 0;
}
else if(0==node.getAttribute("flag")&& flag == 0){
node.setAttribute('flag',"1");
flag = 1;
node.style.border = "2px solid #fedd00";
document.getElementById('number').innerHTML = 1;
document.getElementById('total-money').innerHTML = node.getAttribute('money');
}
if(0 == flag){
document.getElementById('number').innerHTML = 0;
document.getElementById('total-money').innerHTML = 0;
}
}
});
};
Calendar.prototype._monthPanel = function(date){
//如果传递了Date对象,则按Date对象进行计算月份面板
//否则,按照当前月份计算面板
var myDate = date || new Date(),
year = myDate.getFullYear(),
month = myDate.getMonth(),
day = myDate.getDate(),
week = myDate.getDay(),
currentDays = new Date(year, month + 1, 0).getDate(),
preDays = new Date(year, month, 0).getDate(),
firstDay = new Date(year, month, 1),
firstCell = firstDay.getDay() === 0 ? 6 : firstDay.getDay() - 1,
bottomCell = 42 - currentDays - firstCell;
//前一个月该显示多少天
var preMonth = [];
for(var p = firstCell; p > 0; p--){
preMonth.push(new Date(year, month - 1, preDays - p + 1));
}
var len = preMonth.length;
//本月
var currentMonth = [];
for(var c = 0; c < currentDays; c++){
currentMonth.push(new Date(year, month, c + 1));
}
//下一个月
var nextMonth = [];
for(var n = 0; n < bottomCell; n++){
nextMonth.push(new Date(year, month + 1, n + 1));
}
preMonth = preMonth.concat(currentMonth, nextMonth);
return {
date: preMonth,
preLen: len,
currentLen: currentMonth.length
};
};
global.Calendar = Calendar;
})(window);
这段js是生成日历主体内容结构的。
Calendar.prototype._monthPanel
这个方法可作为一个api来使用,直接生成当月的天数,以及对应的情况。
var Share = React.createClass({
componentDidMount: function() {
var datemoney = new Array();//需要从外部得到的日期价钱对应表
datemoney["2016/03/01"] = "500";
datemoney["2016/03/17"] = "1000";
datemoney["2016/03/25"] = "5400";
datemoney["2016/04/23"] = "4000";
datemoney["2016/04/02"] = "4300";
(function(global){
//var calendar_codeshow = document.getElementById('calendar_codeshow');
var CurDate = new Date();
var year = CurDate.getFullYear();
var month = CurDate.getMonth()+1;
var day = CurDate.getDate();
var arr_date;
var arr_date_2;
for(arr_date in datemoney){
arr_date_2 = arr_date;
break;
}
var date = new Date(arr_date_2);
//日历
var calendar = new Calendar('calendar',date,datemoney);//
calendar.showUI();
$("#pre").on('click',function(e){
var year = parseInt(date.getFullYear()),
month = parseInt(date.getMonth());
if(month == 0){
date = new Date(year - 1, 11, 1);
}else{
date = new Date(year, month - 1, 1);
}
calendar = new Calendar('calendar',date,datemoney);//
calendar.showUI();
});
$("#next").on('click',function(e){
var year = parseInt(date.getFullYear()),
month = parseInt(date.getMonth());
if(month === 11){
date = new Date(year + 1, 0, 1);
}else{
date = new Date(year, month + 1, 1);
}
calendar = new Calendar('calendar',date,datemoney);//
calendar.showUI();
});
$('#add').on("click",function(e){
for(var i=0;i<42;i++){
var aim = document.getElementById('day'+i);
if(aim!=null && aim.getAttribute("flag") == 1){
//alert("if"+1 == flag && 1==aim.getAttribute("flag"));
//alert("e"+document.getElementById('number').innerHTML);
var money = parseInt(aim.getAttribute('money'));
if(1 == flag && 1==aim.getAttribute("flag")){
document.getElementById('number').innerHTML++;
//alert(document.getElementById('number').innerHTML);
var number = parseInt(document.getElementById('number').innerHTML);
document.getElementById('total-money').innerHTML = money * number;
//callback(money*number,number);
}
}
}
});
$('#reduce').on("click",function(e){
if(parseInt(document.getElementById('number').innerHTML)>1){
for(var i=0;i<42;i++){
var aim = document.getElementById('day'+i);
if(aim!=null && aim.getAttribute("flag") == 1){
var money = parseInt(aim.getAttribute('money'));
document.getElementById('number').innerHTML--;
var number = parseInt(document.getElementById('number').innerHTML);
//alert(money);
document.getElementById('total-money').innerHTML = money * number;
//callback(money*number,number);
}
}}
});
$('.submit').on('click',function(e){
var total_money = document.getElementById('total-money').innerHTML;
var number = document.getElementById('number').innerHTML;
alert(total_money);
alert(number);
});
})(this);
},
render: function(){
return (
<div id="calendar-main">
<div id="header">
<p className = "head-content">选择活动出发日期<button><img className="close" src="http://download.duckr.cn/wechat/service/close_btn.png" /></button></p>
</div>
<div id="calendar">
<table id ="week_table">
<tr>
<td><div>一</div></td>
<td><div>二</div></td>
<td><div>三</div></td>
<td><div>四</div></td>
<td><div>五</div></td>
<td><div>六</div></td>
<td><div>日</div></td>
</tr>
</table>
<table id = "header_table">
<tr>
<td><div id = "pre"><<上月</div></td>
<td><div id = "header_date"></div></td>
<td><div id = "next">下月>></div></td>
</tr>
</table>
</div>
<div id="bottom">
<div id ="reduce-add">购买数量
<button className="reduce"><img id="reduce" src="http://download.duckr.cn/wechat/service/minus_ticket.png"/></button>
<span className="zhang">张</span><span id="number">0</span>
<button className="add"><img id ="add" src="http://download.duckr.cn/wechat/service/add_ticket.png"/></button>
</div>
<button className="submit">支付(¥<span id="total-money">0</span>)</button>
</div>
</div>
);
}
});
React.render(React.createElement(Share , null),
document.getElementById('content'));
这是外部框架的js,也就是在这个js中调用calendar的。
Safari对于js Date函数有一个坑,就是必须用最标准的形式如Date(YYYY/MM/DD),进行初始化,new
Date(
'2011-04-12'
.replace(/-/g,
"/"
))这样就可以。
其他浏览器可以用相对宽松的形式如Date("2012-3-5")这种的都可以解析,很关键!Safari还有很多坑,比如一个在以前提过的,h5media播放器无法自动播放的情况,必须有一个用户的动作才能触发播放。
(在safri on ios里面明确指出等待用户的交互动作后才能播放media,也就是说如果你没有得到用户的action就播放的话就会被safri拦截)
Safari在点击事件(onclick)中还有一个坑,需要给你的dom写一个css样式 cursor:pointer,因为safari认为这才是一个可点击区域。但是好像使用jQuery on绑定的点击事件就没有问题。。
最后还有个布局上的收获,如果需要在底部加一个其他颜色的蒙版,像最上面那个灰黑色蒙版,这时候不能用background-color+opacity,因为这样会使它下面所有的子div都是变透明,而应该在外面大div中使用css3中给出的rgba(0,0,0,0.7),前面三个代表颜色,最后一个代表透明度,用这种方法就是只在父div中有透明度。nice!
关于布局中的居中问题,可以参考下面这段话:
让行内元素水平居中显示,我们需要为其父级元素设置text-align:center,一般这个属性是用于将文字水平居中的,我们的行内元素就相当于一行之内的文字了,所以可以使用这个方法。
让块级元素,水平居中的办法是为块元素本身添加margin:0 auto;这样块级元素的左右边距就是自动的,也就可以在是水平方向上居中了。
不管是inline-block还是block,我们需要理解其居中的原理,是inline-block,就对其父级元素添加text-align:center,是块级元素就对其本身添加margin:0 auto;记住了这些,以后再对元素进行居中,居左,居右的时候就不用担心自己不会啦。