Javascript的DOM中兼容问题以及解决兼容问题的方法 一、获取非行内样式的方法和它的兼容问题及解决方式 二、获取事件对象的方法和它的兼容问题及解决方式 三、阻止事件冒泡的方法和它的兼容问题以及解决方式 四、键盘事件的兼容问题以及解决方式 五、阻止默认事件的方法和它的兼容问题以及解决方式 六、事件监听器 七、事件委托中事件源的兼容问题

方 法 一:getComputedStyle(obox,false) 

第一个参数表示要获取的对象,第二个值指定一个要匹配的伪元素的字符串。必须对普通元素省略(或null)false也可以。主要针对正常浏览器

方 法 二:Element.currentStyle  在IE浏览器中使用

解决兼容问题的方式:

function getStyle(ele,attr){
    if(ele.currentStyle){
        return ele.currentStyle[attr];
    }else{
        return getComputedStyle(ele,false)[attr];
    }
}

案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
         #box{100px;height:100px;border: solid 1px black;}
    </style>
</head>
<body>
        <div id="box" style="background: red"></div>
</body>
<script>
    var obox = document.getElementById("box")
    // 行内样式;是可以获取和设置的
    console.log(obox.style.background);// red
    // 用style操作获取不了非行内样式
    console.log(obox.style.border);// 为空

    // 如何获取非行内样式,只能获取不能设置;
    // Window.getComputedStyle()方法返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计
    // 算后报告元素的所有CSS属性的值。 私有的CSS属性值可以通过对象提供的API或通过简单地使用CSS属性名称进行索引来访问。
    console.log(getComputedStyle(obox,null));
    //第一个参数表示要获取的对象,第二个值指定一个要匹配的伪元素的字符串。必须对普通元素省略(或null)false也可以。
    console.log(getComputedStyle(obox,null).width);//100px;

    // 由于getComputedStyle()存在兼容,另一个获取方法
    // Element.currentStyle可以在ie里用
    console.log(obox.currentStyle);//undefined
    // console.log(obox.currentStyle.width)


    // 为了解决兼容问题,可以将这两种放进一个封装函数中

    function getStyle(ele,attr){
        var a = "";
        if(ele.currentStyle){
            a = ele.currentStyle[attr];//attr是一个变量,变量用中括号
        }else {
            a = getComputedStyle(ele,false)[attr];
        }
        return a;
    }



    getStyle(obox,"width")


    // 简易写法
    function getStyle(ele,attr){
        
        if(ele.currentStyle){
            return ele.currentStyle[attr];//attr是一个变量,变量用中括号
        }else {
            return getComputedStyle(ele,false)[attr];
        }
    }



    getStyle(obox,"width")
    
    // 这样绝大部分浏览器兼容问题就解决了
    
    
</script>
</html>

二、获取事件对象的方法和它的兼容问题及解决方式

1.IE中:          window.event
 
2.正常浏览器中:    对象.on事件 = function(event){}
 
解决兼容问题的方式:
    document.onclick = function(eve){
       var e = eve || window.event;
   }

案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box{100px;height:100px;background: red;}
    </style>
</head>
<body>
    <div class="box"></div>
</body>
<script>
    
    // 如何获取事件对象?
    // 给事件处理函数一个形参;
    var obox = document.querySelector(".box") 

    // obox.onclick = function(abc){
    //     console.log(abc)
    // }
    // obox.onclick = function(){
    //     console.log(window.event)  //可以在ie使用;
    // }

    // 解决兼容

    obox.onclick = function(eve){
        var e = eve || window.event;
        console.log(e);//通过event获得一个对象
        
    }

    
</script>
</html>

三、阻止事件冒泡的方法和它的兼容问题以及解决方式

方 法 一:eve.stopPropagation(); 主要针对正常浏览器

方 法 二:eve.cancelBubble = true; 在IE浏览器中使用

解决兼容问题的方式:

function stopBubble(e){
        if(e.stopPropagation){
            e.stopPropagation();
        }else{
            e.cancelBubble = true;
        }
    }

 案例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box1 {
             400px;
            height: 400px;
            background: red
        }

        .box2 {
             300px;
            height: 300px;
            background: blue
        }

        .box3 {
             200px;
            height: 200px;
            background: green
        }
    </style>
</head>

<body>
    <div class="box1">
        <div class="box2">
            <div class="box3"></div>
        </div>
    </div>
</body>
<script>
    // 事件冒泡
    // 当触发某个元素的某个事件时,它会先触发自己的对应事件,然后,“依次向上”触发所有父级的“相同事件”,如果中间有父级没有“相同事件”,继续向上触发
    // 事件流:事件执行顺序我们叫他事件流。
    // 事件流中事件冒泡的由来:IE公司认为,如果你面前有个靶子,你的飞镖射中了其中一环,并不仅仅是只对这一环产生了操作,而是对整个靶子都产生了操作。

    // 所以,当 最里面 的元素触发了事件的时候,会依次向上触发所有元素的相同事件(从触发事件的元素开始一直向上触发),但是事件冒泡对我们几乎没有任何好处,
    // 所以我们需要阻止事件冒泡。

    //阻止事件冒泡的两种方法
    // eve.stopPropagation();            
    // eve.cancelBubble = true;        //兼容IE

    // 解决兼容问题:封装一个函数
    function stopBubble(e){
        if(e.stopPropagation){
            e.stopPropagation();
        }else{
            e.cancelBubble = true;
        }
    }

    var obox1 = document.querySelector(".box1");
    var obox2 = document.querySelector(".box2");
    var obox3 = document.querySelector(".box3");

    obox1.onclick = function(eve){
        var e = eve || window.event;
        stopBubble(e);
        alert("red");
    }

    obox2.onclick = function(eve){
        var e = eve || window.event;
        stopBubble(e);
        alert("blue");
    }

    obox3.onclick = function(eve){
        var e = eve || window.event;
        stopBubble(e);
        alert("green");
    }

</script>
</html>

四、键盘事件的兼容问题以及解决方式

解决兼容问题的方式:
var e = eve || window.event;
var code = eve.keyCode || window.which;

案例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box {
             100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 0;
            top: 0;
        }
    </style>
</head>
<body>
    <div class="box"></div>
</body>
<script>
    // 和鼠标事件一样,键盘事件也存在兼容;
    // var e = eve || window.event;
    // var code = e.keyCode || e.which;

    // 案例:通过键盘上下左右,控制页面中的元素位置移动

    var obox = document.querySelector("div");
    // 这个div并没有焦点;所以:
    //先创一个事件对象;
    document.onkeydown = function(eve){
        var e = eve || window.event;
        var code = eve.keyCode || window.which;

        // 这里通过选择语句中的switch();
        switch(code){
            // 获取元素与父元素之间的偏移距离;用offsetLeft/offsetTop;
            case 37 : //左键
            obox.style.left = obox.offsetLeft-10 + "px";break;
            case 38 : //上键
            obox.style.top = obox.offsetTop-10 + "px";break;
            case 39 : //右键
            obox.style.left = obox.offsetLeft+10 + "px";break; // 向上向右就是+10;
            case 40 : //下键
            obox.style.top = obox.offsetTop+10 + "px";break;
        }
    }
</script>
</html>

五、阻止默认事件的方法和它的兼容问题以及解决方式

方 法 一:

e.preventDefault();
window.event.returnValue = false;

方 法 二:

在事件处理函数的最后加上 return false;
 
解决兼容问题的方式:
function stopDefault(e){
    if(e.preventDefault){
        e.preventDefault()
    }else{
        e.returnValue = false;
    }
}

案例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box {
             120px;
            height: 220px;
            background: #fff;
            border: 1px solid #000;
            position: absolute;
            left: 0;
            right: 0;
            display: none;
        }
        .box ul {
            margin: 0;
        }
    </style>
</head>
<body>
    <div class="box">
        <ul>
            <li>刷新</li>
            <li>复制</li>
            <li>粘贴</li>
            <li>剪切</li>
            <li>删除</li>
        </ul>
    </div>
</body>
<script>
    // 浏览器默认行为;
    // 默认事件:就是浏览器自己触发的事件。比如:a链接的跳转,form提交时的跳转,鼠标右键菜单。
    // 当触发鼠标的右键事件时,会弹出右键菜单,这就是默认事件情况之一;

    // 如何阻止默认事件两种方法
    //一、解决兼容
    // e.preventDefault()();
    // window.event.returnValue = false;

    // 二、
    // 在事件处理函数的最后加上 return false;


    // 案例:自定义右键菜单

    // oncontextmenu 鼠标点击右键;
    var obox = document.querySelector(".box");
    // 给阻止事件的方法封装为一个函数
    function stopDefault(e){
        if(e.preventDefault){
            e.preventDefault();
        }else{
            e.returnValue = false;
        }
    }

    document.oncontextmenu = function(eve){
        var e = eve || window.event;
        
        obox.style.display = "block";
        // 阻止默认设置
        // stopDefault(e);
    
        obox.style.left = e.offsetX + "px";
        obox.style.top = e.offsetY + "px";
        //return false 也可以阻止默认事件:必须函数里的最后一位
        return false;

    }

    document.onclick = function(){
        obox.style.display = "none";
    }

    function stopDefault(e){
        if(e.preventDefault){
            e.preventDefault();
        }else{
            e.returnValue = false;
        }
    }
</script>
</html>

六、事件监听器

事件触发阶段主要由于事件流:DOM0级事件处理阶段和DOM2级事件处理;
 
    DOM0级事件处理,是一种赋值方式,是被所有浏览器所支持的,简单易懂容易操作;
        元素.onclick = function(){}
 
    DOM2级事件处理是所有DOM节点中的方法,可以重复绑定,但是浏览器兼容存在问题;
 
    非IE下:(这里的事件名不带on),第三个参数表示是在捕获阶段还是冒泡阶段。可以重复绑定事件,执行顺序按照绑定顺序来执行。
 
    oDiv.addEventListener('click',fn,false);
    oDiv.removeEventListener('click',fn ,false);
 
    IE下:
 
    只有冒泡阶段,所以没有第三个参数;(这里的事件名需要加on)
    oDiv.attachEvent();
    oDiv.detachEvent() ;
 
解决兼容问题的方式:
1.封装成对象的方式
    var EventUtil={
        addHandler:function(DOM,EventType,fn){
            if(DOM.addEventListener){
                DOM.addEventListener(EventType,fn,false);
            }else if(DOM.attachEvent){
                DOM.attachEvent('on'+EventType,fn)
            }else{
                DOM['on'+EventType]=fn
            }
        },
        removeHandler:function(DOM,EventType,fn){
            if(DOM.removeEventListener){
                DOM.removeEventListener(EventType,fn,false)
            }else if(DOM.detachEvent){
                DOM.detachEvent('on'+EventType,fn)
            }else{
                DOM['on'+EventType]=null;
            }
        }
    }


2.封装成两个函数的方式
    function addEvent(obj,inci,back){
        if(obj.addEventListener){
            obj.addEventListener(inci,back);
        }else if(obj.attachEvent){
            obj.attachEvent("on" + inci,back);
        }else{
            obj["on"+inci] = back;
        }
    }
          
    function removeEvent(obj,inci,back){
        if(obj.removeEventListener){
            obj.removeEventListener(inci,back,false);
        }else if(obj.detachEvent){
            obj.detachEvent("on" + inci,back);
        }else{
            obj["on"+inci] = null;
        }
    }

案例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box {
             100px;
            height: 100px;
            background: red;
        }
    </style>
</head>

<body>
    <div class="box"></div>
</body>
<script>
    var obox = document.querySelector(".box");
    //  事件触发阶段主要由于事件流:DOM0级事件处理阶段和DOM2级事件处理;
    // DOM0级事件处理,是一种赋值方式,是被所有浏览器所支持的,简单易懂容易操作;
    // 元素.onclick = function(){}

    // 赋值式绑定 (DOM0级事件处理阶段)
    // obox.onclick = function(){
    //     console.log(1);   
    // }

    // obox.onclick = function(){
    //     console.log(2);   
    // }
    // 当你点击元素时,只能获取1,2中的一个值;
    // 删除赋值式事件绑定;
    // obox.onclick = null;
    // 特点:常用,没有兼容,简单

    
    // 监听式绑定(DOM2级事件处理):可以重复绑定;
    // 非IE下:(这里的事件名不带on),第三个参数表示是在捕获阶段还是冒泡阶段。可以重复绑定事件,执行顺序按照绑定顺序来执行。

    
    // EventTarget.addEventListener() 方法将指定的监听器注册到 EventTarget 上,
    // 当该对象触发指定的事件时,指定的回调函数就会被执行。
    // oDiv.addEventListener('click', fn, false);
    // 第一个参数表示:表示监听事件类型的 字符串 。
   
    // 第二个参数表示:当所监听的事件类型触发时,会接收到一个事件通知(实现了 Event 接口的对象)对象。listener 必须是一个实现了 EventListener 接口的对象,或者是一个函数。
    
    // 第三个参数表示:当第三个参数(设为true) 时,沿着DOM树向上冒泡的事件,不会触发listener。当一个元素嵌套了另一个元素,
    // 并且两个元素都对同一事件注册了一个处理函数时,所发生的事件 冒泡和事件捕获 是两种不同的事件传播方式。事件传播模式决定了元素以哪个顺序接收事件。
    // 第三个参数可写可不写;

    // oDiv.removeEventListener('click', fn, false);
    // 删除使用 EventTarget.addEventListener() 方法添加的事件。
    
    // IE下:

    // 只有冒泡阶段, 所以没有第三个参数;(这里的事件名需要加on)
    // oDiv.attachEvent() ;
    // oDiv.detachEvent();

    // 冒泡:从下往上(从里往外)
    // 捕获:从上往下(从外往内)

    // 如何解决兼容问题
    // 将对象放入到括号内
    // cb表示事件处理函数
    function removeEvent(ele,type,cb){
        if(ele.removeEventListener){
            ele.removeEventListener(type,cb)
        }else if(ele.detachEvent){
            ele.detachEvent("on"+type,cb)
        }else{
            ele["on"+type] = null;
        }
    }

    function addEvent(ele,type,cb){
        if(ele.addEventListener){
            ele.addEventListener(type,cb)
        }else if(ele.attachEvent){
            ele.attachEvent("on"+type,cb)
        }else{
            ele["on"+type] = cb;
        }
    }

    



</script>

</html>

七、事件委托中事件源的兼容问题

解决兼容问题的方式:
 
var t = e.target || e.srcElement; 

案例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        ul {
            background: #ccc
        }

        li {
            padding: 10px 0;
            margin: 10px 0;
            background: red
        }
    </style>
</head>

<body>
    <ul>
        <li>link1</li>
        <li abc="l">link2</li>
        <li abc="l">link3</li>
        <li abc="l">link4</li>
        <li>link5</li>
    </ul>
</body>
<script>
    var ali = document.querySelectorAll("ul li");

    var oul = document.querySelector("ul")
    oul.onclick = function(eve){
        var e = eve || window.event;

        var t = e.target || e.srcElement;   // 也是一种兼容

        if(t.getAttribute("abc") == "l"){
            console.log(e.target.innerHTML)
        }
        
    }
</script>
</html>