• JavaScript 常见的事件冲突解决方案,日历Demo


    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>
  • 相关阅读:
    搭建自己的技术博客系列(三)让你的博客拥有评论功能!
    搭建自己的技术博客系列(二)把 Hexo 博客部署到 GitHub 上
    Excel2003 去除重复项
    Delphi 7拦截滚轮事件不响应滚轮的上下滚动
    APSC4xSeries_Ver32.exe在win764位提示缺少DLL错误解决办法
    Win7装在其他盘 (非C盘)办法
    Delphi7 安装ICS,与简单使用
    Python学习笔记
    使用IP spoofer 功能
    python在windows里怎么配置apache呢,
  • 原文地址:https://www.cnblogs.com/zsben991126/p/13061050.html
Copyright © 2020-2023  润新知