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='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'> "+ "<tr>"+ "<td colspan='7' class='TrOut'>"+ //带有前进后退按钮的首行 "<table width='100%' height='100%'border='0' cellpadding='0' cellspacing='0'>"+ "<tr align='center'> "+ "<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> "+ "<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> "+ "<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> "+ "<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> "+ "</td>"+ "</tr> "+ "<tr align='center'> "; //添加一星期每天的名称格子 for(var i=0;i<7;i++) this.DStr+="<td class='TrOut'>"+DateArray[i]+"</td> "; this.DStr+="</tr> "; //添加下面六行日期格子,当前日期需要特别标注出来 for(var i=0;i<6;i++){ this.DStr+="<tr align='center'> "; 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> "; } this.DStr+="</tr> "; } 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> "; } // 当点击了某选项时就重新将下方日历重写,当焦点移开时就将其值变为一个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='67'> "+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> "; obj.innerHTML="<select id='select2' style='47'> "+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>