web课布置了个作业,给一份全是bug的日历,要解决chrome上的事件冲突问题
ps:事件冲突解决起来真的很麻烦
1.onblur 和 onclick冲突
onclick 相当于 在某一元素上触发了 onmousedown(即鼠标按下)后 任然在该元素 上 触发了onmouseup(鼠标按键弹起)才触发 onclick;
对于某元素A 绑定了 click事件 并同时对另外 的元素B 绑定onblur事件,
这时候,当在A上mousedown后,即触发了B元素的onblur事件,该事件函数执行后的效果是 改变了DOM结构,
使得鼠标已经不在在元素A之上。 这时鼠标任然没有mouseup ,在mouseup之后,以为会触发click事件,实际上却不能触发。
解决方案:要保证onclick先于给onblur被触发的话,给onblur弄个setTimeout ,即让它延时一会,等onclick处理完后,立刻clear这个Timeout,就能立即触发onblur时间
2.子节点和父节点同时触发onclick
如果子节点和父节点同时都注册了onclick等事件,那么在chrome上,单击子节点时会同时触发父子结点的onclick
解决方案:如果仅仅想触发子节点的而不触发父节点的,那么就在子节点的onmousedown事件里,把父节点的onclick事件取消了(如设一个空函数)
再在子节点的onmouseup事件里,把父节点原来的onclick事件注册给它就可以了
<!DOCTYPE html>
<html>
<head>
<meta charset=”gbk">
</head>
<body>
</body>
</html>
<style type="text/css">
.body, td{
font-family:"Arial";
font-size:8pt;
color:#000000;
}
.TrOut{
border-left:1px solid #f4f4f4;
border-right:1px solid #999999;
border-top:1px solid #f4f4f4;
border-bottom:1px solid #999999;
background:#dddddd;
height:26;
}
.TdOver{
border-left:1px
solid #9c9c9c;
border-right:1px
solid #ffffff;
border-top:1px
solid #9c9c9c;
border-bottom:1px solid #ffffff;
background:#eeeeee;
height:20;
}
.TdOut{
border-left:1px solid #ffffff;
border-right:1px solid #9c9c9c;
border-top:1px solid #ffffff;
border-bottom:1px solid #9c9c9c;
background:#eeeeee; height:20;
}
</style>
<script language="JScript">
/*********************************************************
迷你绽?.0版本
如果下列代码发现bug请联系 Flashsoft2000@hotmail.com
函数 TableFunction 提供以下方法和属性:
1.GetDateStr()返回指定年月的日期的数组,包括空字符.
参数:
y是指年
m是指月
调用方式:TableFunction().GetDateStr(Year,Month)
2.GetTableStr()返回指定年月的已经格式化了的表格
参数:
y是指年
m是指月
调用方式:TableFunction().GetTableStr(Year,Month)
3.WriteSelect()返回年月的选择框
参数:
obj是指需要加入选择框的容器
values是指需要加亮的项目
action是指参数,带入参数y表示是年选择框,带入参数m表示月选择框
getobj是指在哪个控件上触发的事件,其中true为非当前选择框触发
而false则为当前选择框触发
调用方式:TableFunction().WriteSelect(obj,values,action,getobj)
4.RewriteTableStr() 复位重写表格中的日期
参数:
y是指年
m是指月
调用方式:TableFunction().RewriteTableStr(Year,Month)
5.JumpToRun() 左右控制表格中的月变化
参数:
action表示日历是前进还是后退
调用方式:TableFunction().JumpToRun(action)
6.AlertDay()提示当前点击的位置的日期
参数:无
调用方式:TableFunction().AlertDay()
*********************************************************/
function TableFunction(){
/*
1.GetDateStr()返回指定年月的日期的数组,包括空字符.
参数:
y是指年
m是指月
调用方式:TableFunction().GetDateStr(Year,Month)
*/
this.GetDateStr=function(y,m){
this.DayArray=[];
for(var i=0;i<42;i++)this.DayArray[i]=" ";
for(var i=0;i<new Date(y,m,0).getDate();i++) // new Date(y,m,0).getDate():得到该月最大天数
this.DayArray[i+new Date(y,m-1,1).getDay()]=i+1; // new Date(y,m-1,1).getDay() 该月第一天是星期几
return this.DayArray;
}
/*
2.GetTableStr()返回指定年月的已经格式化了的表格
参数:
y是指年
m是指月
调用方式:TableFunction().GetTableStr(Year,Month)
oncontextmenu:右键单击触发
onselectstart:触发时间为目标对象被开始选中时
colspan:列数
webdings:类似图标控件库,可用数字代替图标
onmouseover:当鼠标放上时
onmouseout:当鼠标移出时
TdOver:当前天或鼠标滑过的那个格子
TdOut:非当前天或鼠标未滑过的那个格子
*/
this.GetTableStr=function(y,m){
this.DateArray=["日","一","二","三","四","五","六"];
this.DStr=
"<table oncontextmenu='return false' onselectstart='return false' style='width:160;cursor:default;border:1 solid #9c9c9c;border-right:0;border-bottom:0;filter:progid:dximagetransform.microsoft.dropshadow(color=#e3e3e3,offx=3,offy=3,positive=true)' border='0' cellpadding='0' cellspacing='0'>\n"+
"<tr>"+
"<td colspan='7' class='TrOut'>"+
//带有前进后退按钮的首行
"<table width='100%' height='100%'border='0' cellpadding='0' cellspacing='0'>"+
"<tr align='center'>\n"+
"<td width='20' style='font-family:\"webdings\";font-size:9pt' onclick='TableFunction().JumpToRun(\"b\")' onmouseover='this.style.color=\"#ff9900\"' onmouseout='this.style.color=\"\"'>3</td>\n"+
"<td id='YearTD' width='70' onmouseover='this.style.background=\"#cccccc\"' onmouseout='this.style.background=\"\"' onmouseup='TableFunction().WriteSelect(this,this.innerText.split(\" \")[0],\"y\",false)'>"+y+" 年</td>\n"+
"<td id='MonthTD' width='47' onmouseover='this.style.background=\"#cccccc\"' onmouseout='this.style.background=\"\"' onmouseup='TableFunction().WriteSelect(this,this.innerText.split(\" \")[0],\"m\",false)'>"+m+" 月</td>\n"+
"<td width='20' style='font-family:\"webdings\";font-size:9pt' onclick='TableFunction().JumpToRun(\"n\")' onmouseover='this.style.color=\"#ff9900\"' onmouseout='this.style.color=\"\"'>4</td>"+
"</tr>"+
"</table>\n"+
"</td>"+
"</tr>\n"+
"<tr align='center'>\n";
//添加一星期每天的名称格子
for(var i=0;i<7;i++)
this.DStr+="<td class='TrOut'>"+DateArray[i]+"</td>\n";
this.DStr+="</tr>\n";
//添加下面六行日期格子,当前日期需要特别标注出来
for(var i=0;i<6;i++){
this.DStr+="<tr align='center'>\n";
for(var j=0;j<7;j++){
var CS=new Date().getDate()==this.GetDateStr(y,m)[i*7+j]?"TdOver":"TdOut";
this.DStr+="<td id='TD' class='"+CS+"' cs='"+CS+"' onmouseover='this.className=\"TdOver\"' onmouseout='if(this.cs!=\"TdOver\")this.className=\"TdOut\"' onclick='TableFunction().AlertDay()'>"+this.GetDateStr(y,m)[i*7+j]+"</td>\n";
}
this.DStr+="</tr>\n";
}
this.DStr+="</table>";
return this.DStr;
}
/*
3.WriteSelect()返回年月的选择框
参数:
obj是指需要加入选择框的容器
values是指需要加亮的项目
action是指参数,带入参数y表示是年选择框,带入参数m表示月选择框
getobj是指在哪个控件上触发的事件,其中true为非当前选择框触发
而false则为当前选择框触发
调用方式:TableFunction().WriteSelect(obj,values,action,getobj)
这里的流程:首先YearTD在未点击前的innerHTML是“120年”这样的内容
在点击后,即触发了onmouseup,就会进入该函数,此时参数getobj是false
进入函数后,由于getobj=false,所以YearTD的innerHtml被改为select标签,并且给select设置onblur,onchange事件
当选择了option的某一项后,需要更新下放日期格子的值,
所以调用onblur,将YearTD的innerHTML值改为选中的那一项option的值
然后再次调用该函数,此时getobj是true,表示要进行的操作是更新日历
此时传入的obj任然是YearTD,然后我们在函数中调用RewriteTableStr去更新日历就可以
*/
this.WriteSelect=function(obj,values,action,getobj){
console.log(obj);
if(values=="")return;
if(getobj){//如果是要显示更新的日历,则直接更新下方日期
if(action=="y")YearTD.innerHTML=values+" 年";
else MonthTD.innerHTML=values+" 月";
var y=YearTD.innerHTML.split(" ")[0],m=MonthTD.innerHTML.split(" ")[0];
this.RewriteTableStr(y,m);
return false;
}
var StrArray=[];
if(action=="y"){
for(var i=0;i<15;i++){
var year=values-7+i;
StrArray[i]="<option value='"+year+"' "+(values==year?"selected":"")+"> "+year+"年</option>\n";
}
// 当点击了某选项时就重新将下方日历重写,当焦点移开时就将其值变为一个select下拉框,注意此时select仍处于onblur状态
// 在chrome 中,onclick被onblur冲突,导致点了一下下拉列表,弹出后马上被onblur冲突导致收回
/*onclick 相当于 在某一元素上触发了 onmousedown(即鼠标按下)后 任然在该元素 上 触发了onmouseup(鼠标按键弹起)才触发 onclick;
对于某元素A 绑定了 click事件 并同时对另外 的元素B 绑定onblur事件,
这时候,当在A上mousedown后,即触发了B元素的onblur事件,该事件函数执行后的效果是 改变了DOM结构,
使得鼠标已经不在在元素A之上。 这时鼠标任然没有mouseup ,在mouseup之后,以为会触发click事件,实际上却不能触发。
*/
obj.innerHTML="<select id='select1' style='width:67'>\n"+StrArray.join("")+"</select>";
/*
这一块的逻辑:此时YearTD的innerHTML已经是select标签,而select标签有onmousedown类似事件用来弹出下拉列表
正常操作下,onmousedown操作后必定有onmouseup操作
而select的onmouseup又会触发父节点YearTD注册的onmouseup事件(如果在select处按下鼠标,然后再把鼠标移到其他地方释放,就不会触发YearTD的onmouseup,但是这不是正常人的操作。。),
导致又重新进入了一次这个函数,这显然是不正确的
因此我们要在select触发onmousedown事件后,将父节点YearTD的onmouseup先给取消掉防止其触发
然后在select触发onchange后,我们再将父节点YearTD的onmouseup给注册回来,这样就不影响后续其他操作
*/
select1.onmousedown=function(){
var parent=this.parentNode;
parent.onmouseup=function(){};
}
select1.onchange=function(){
var parent=this.parentNode;
YearTD.innerText=this.value+" 年";
TableFunction().WriteSelect(parent,this.value,"y",true);
parent.onmouseup=function(){
TableFunction().WriteSelect(this,this.innerText.split(" ")[0],"y",false);
}
};
select1.focus();
}
if(action=="m"){
for(var i=1;i<13;i++)
StrArray[i]="<option value='"+i+"' "+(i==values?"selected":"")+"> "+i+"月</option>\n";
obj.innerHTML="<select id='select2' style='width:47'>\n"+StrArray.join("")+"</select>";
select2.onmousedown=function(){
var parent=this.parentNode;
parent.onmouseup=function(){};
}
select2.onchange=function(){
var parent=this.parentNode;
MonthTD.innerText=this.value+" 月";
TableFunction().WriteSelect(parent,this.value,"m",true);
parent.onmouseup=function(){
TableFunction().WriteSelect(this,this.innerText.split(" ")[0],"m",false);
}
};
select2.focus();
}
}
/*
4.RewriteTableStr() 复位重写表格中的日期
参数:
y是指年
m是指月
调用方式:TableFunction().RewriteTableStr(Year,Month)
*/
this.RewriteTableStr=function(y,m){
var TArray=this.GetDateStr(y,m);
var len=TArray.length;
for(var i=0;i<len;i++){
TD[i].innerHTML=TArray[i];
TD[i].className="TdOut";
TD[i].cs="TdOut";
if(new Date().getYear()==y&&new Date().getMonth()+1==m&&new Date().getDate()==TArray[i]){
TD[i].className="TdOver";
TD[i].cs="TdOver";
}
}
}
/*
5.JumpToRun() 左右控制表格中的月变化
参数:
action表示日历是前进还是后退
调用方式:TableFunction().JumpToRun(action)
*/
this.JumpToRun=function(action){
var YearNO=YearTD.innerText.split(' ')[0];
var MonthNO=MonthTD.innerText.split(' ')[0];
if(action=="b"){ //后退一个月
if(MonthNO=="1"){
MonthNO=13;
YearNO=YearNO-1;
}
MonthTD.innerText=MonthNO-1+" 月";
YearTD.innerText=YearNO+" 年";
this.RewriteTableStr(YearNO,MonthNO-1);//更新下面格子里的日期
}
if(action=="n"){ //前进一个月
if(MonthNO=="12"){
MonthNO=0;
YearNO=YearNO-(-1);
}
YearTD.innerText=YearNO+" 年";
MonthTD.innerText=MonthNO-(-1)+" 月";
this.RewriteTableStr(YearNO,MonthNO-(-1));
}
}
/*
6.AlertDay()提示当前点击的位置的日期
参数:无
调用方式:TableFunction().AlertDay()
*/
this.AlertDay=function(){
if(event.srcElement.innerText!=" ")
alert(YearTD.innerText.split(' ')[0]+"年"+MonthTD.innerText.split(' ')[0]+"月"+event.srcElement.innerText+"日");
}
return this;
}
document.write(TableFunction().GetTableStr(new Date().getYear(),new Date().getMonth()+1));
</script>