# JS 中的浏览器兼容问题及其处理方式

# 1.宽高问题

var winW = document.body.clientWidth || document.docuemntElement.clientWidth; //网页可见区域宽
var winH = document.body.clientHeight || document.docuemntElement.clientHeight; //网页可见区域宽
//以上为不包括边框的宽高,如果是offsetWidth或者offsetHeight的话包括边框

var winWW = document.body.scrollWidth || document.docuemntElement.scrollWidth; //整个网页的宽
var winHH = document.body.scrollHeight || document.docuemntElement.scrollHeight; //整个网页的高

var scrollHeight =
  document.body.scrollTop || document.docuemntElement.scrollTop; //网页被卷去的高
var scrollLeft =
  document.body.scrollLeft || document.docuemntElement.scrollLeft; //网页左卷的距离

var screenH = window.screen.height; //屏幕分辨率的高
var screenW = window.screen.width; //屏幕分辨率的宽
var screenX = window.screenLeft; //浏览器窗口相对于屏幕的x坐标(除了FireFox)
var screenXX = window.screenX; //FireFox相对于屏幕的X坐标
var screenY = window.screenTop; //浏览器窗口相对于屏幕的y坐标(除了FireFox)
var screenYY = window.screenY; //FireFox相对于屏幕的y坐标
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 2.event 事件问题

1) 添加事件/移除事件方法

//  添加事件
addHandler:function(element,type,handler){
    if(element.addEventListener){
        element.addEventListener(type,handler,false)
    }else if(element.attachEvent){
        element.attachEvent("on"+type,handler)
    }else{
        element["on"+type]=handler
    }
}
// 移除事件方法
removeHandler:function(element,type,handler){
    if(element.removeEventListener){
        element.removeEventListener(type,handler,false)
    }else if(element.detachEvent){
        element.detachEvent("on"+type,handler)
    }else{
         element["on"+type]=null
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

分别检验是否是 DOM2 级,IE、DOM0 级。

  • DOM0级:将一个函数赋给一个事件处理程序属性。具有简单、跨浏览器的优势。添加的事件处理程序会在冒泡阶段执行。事件处理程序也是在它所依附的元素作用于中执行。

  • 删除事件处理程序:将事件处理程序的属性的值设为 null。

  • DOM2级:DOM2 级事件处理方法:addEventListener()removeEventListener(),这两种方法 接受三个参数,要处理的事件名,作为事件处理程序的函数和一个布尔值,布尔值为true时,表示在捕获阶段调用事件处理函数;布尔值为false,表示在冒泡阶段调用事件处理函数。 调用addEventListener()添加的事件处理程序只能通过removeEventListener()移除,移除时传入的参数和添加处理程序时使用的参数必须一致。所以通过addEventListener()添加的匿名函数无法移除。与 DOM0 级相同,事件处理程序也是在它所依附的元素作用于中执行。 大多数情况下将事件处理程序添加到事件流的冒泡阶段,可以最大限度的兼容各种浏览器。

  • IE 事件处理程序:两个方法:attachEvent()detachEvent()。接收两个参数:要处理的事件名,作为事件处理程序的函数。与上述两种情况的主要区别是作用域不同:attachEvent()detachEvent()会在全局作用域中执行。 除了作用域的区别外,DOM2级IE事件处理程序可以添加多个事件处理程序,而OM0级只能添加一个。

2) 获取事件及事件对象目标

// 获取事件对象的兼容性写法
getEvent:function(event){
    return event?event:window.event
}
getTarget:function(event){
    return event.target||event.srcElement
}
// 获取事件对象目标的兼容性写法
1
2
3
4
5
6
7
8

event:事件处理对象,包含与创建它的特定事件有关的属性和方法。其中 target(事件的目标)是其中一个成员。 在兼容 DOM 的浏览器中,event 对象只是简单的传入和返回。而 IE 中,event 参数是为定义的,因此就会返回window.event。 返回事件的目标,IE 中为event.srcElemnt

3) 阻止浏览器默认事件及阻止冒泡的兼容性写法

//  阻止浏览器默认事件兼容性写法
preventDefault: funcion(event){
     var event=event||window.event;
    if(event.preventDefault){
        event.preventDafault()
    }else{
        // IE
        event.returnValue=false
    }
}
// 阻止冒泡的兼容性写法
stopPropagation:function(event){
    var event=event||window.event;
    if(event.stopPropagation){
        // stopPropagatation()既能阻止事件冒泡也能阻止事件捕获
        event.stopPropagation()
    }else{
        event.cancelBubble=true
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

4) 获取mouseovermouseout事件相关元素信息

getRelatedTarget: function(event){
                if (event.relatedTarget)
                {
                    return event.relatedTarget;//标准下返回相关元素
                }else if (event.toElement)
                {
                    return event.toElement;//mouseout事件触发,保存相关元素
                }else if (event.fromElement)
                {
                    return event.fromElement;//mouseover事件触发,保存相关元素
                }
            }
1
2
3
4
5
6
7
8
9
10
11
12

DOM 通过event对象的relatedTarget属性提供了相关元素的信息。这个属性只对mouseovermouseout事件才包含值,对于其他事件,这个属性值为 null。在mouseover事件触发时,IE 的fromElement属性保存了相关元素,在mouseout事件触发时,IE 的 toElement 属性保存了相关元素。 5) 跨浏览器获得字符编码

getCharCode:function(event){
    if(typeof event.charCode=='number'){
        return event.charCode
    }else{
        return event.keyCode
    }
}
1
2
3
4
5
6
7

IE9,Firefox,Chrome,Safari 的 event 对象都支持 charcode 属性,在发生keypress事件时才包含值。值为按下那个键所对应的 ASCII 编码。IE8 及之前版本和 Opera 则使用 keyCode。

6) 访问、设置剪切板中的数据

// 访问剪切板中的数据
getClipboardText:function(event){
    var clipboardData=(event.clipboardData||window.clipboardData)
    return clipboardData.getData("text")
}
//设置剪切板中的数据
setClipboardText:function(event,value){
    if(event.clipboardData){
        return event.clipboardData.setData("text/plain",value)
    }else if(window.clipboardData){
        return window.clipboardData.setData("text",value)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

要访问剪切板中的数据,可以使用clipboardData对象:IE 中,这个对象是window对象的属性;而在 Firefox,Chrome,Safar 中,这个对象是event对象的属性

# 3.属性设置

// 该方法FIREFOX支持,IE不支持。
var obj = document.getElementById("objId");
obj.setAttribute("onclick", "funcitonname()");
// IE中必须用点记法来引用所需的事件处理程序,并且要用赋予匿名函数, 如下:
// 这种方法所有浏览器都支持。
var obj = document.getElementById("objId");
obj.onclick = function() {
  fucntionname();
};
1
2
3
4
5
6
7
8
9

# 4.类名设置

class 属性在 W3C DOM 中扮演着很重要的角色,但由于浏览器差异性仍然存在。使用setAttribute("class", vName)语句动态设置 Element 的 class 属性在 firefox 中是行的通的,在 IE 中却不行。因为使用 IE 内核的浏览器不认识class,要改用className; 同样,firefox 也不认识className。所以常用的方法是二者兼备。

// IE和FF都支持object.className。
element.setAttribute("class", vName);
element.setAttribute("className", vName); //for IE
1
2
3

# 5.建立单选钮

IE以外的其他浏览器
var rdo = document.createElement('input');
rdo.setAttribute('type','radio');
rdo.setAttribute('name','radiobtn');
rdo.setAttribute('value','checked');
IE浏览器
var rdo =document.createElement(<input name=”radiobtn” type=”radio” value=”checked” />);
1
2
3
4
5
6
7

# 6.innerText 的问题

问题说明:innerText 在 IE 中能正常工作,但是 innerText 在 FireFox 中却不行。 解决方法:在非 IE 浏览器中使用textContent代替innerText。 示例:

if (navigator.appName.indexOf("Explorer") > -1) {
  document.getElementById("element").innerText = "my text";
} else {
  document.getElementById("element").textContent = "my text";
}
1
2
3
4
5

# 7.Table 操作问题

ie、firefox 以及其它浏览器对于 table 标签的操作都各不相同,在 ie 中不允许对tabletrinnerHTML赋值,使用 js 增加一个 tr 时,使用appendChild方法也不管用,document.appendChild在往表里插入行时 FIREFOX 支持,IE 不支持。

访问的父元素的区别:在IE下,使用 obj.parentElementobj.parentNode 访问 obj 的父结点;在 firefox 下,使用 obj.parentNode访问 obj 的父结点。

解决方法:因为 firefox 与 IE 都支持 DOM,因此统一使用obj.parentNode 来访问 obj 的父结点。

# 8.event.x 与 event.y 问题

问题说明:IE下,even 对象x、y 属性,但是没有pageX、pageY 属性;Firefox下,even 对象pageX、pageY 属性,但是没有x、y 属性。 解决方法:

var myX = event.x ? event.x : event.pageX;
var myY = event.y ? event.y : event.pageY;
1
2

# 9.document.formName.item(”itemName”) 问题

问题说明:IE下,可以使用 document.formName.item(”itemName”)document.formName.elements ["elementName"]; Firefox 下,只能使用document.formName.elements["elementName"]。

解决方法: 统一使用 document.formName.elements["elementName"]。

# 10.自定义属性问题

问题说明:IE 下,可以使用获取常规属性的方法来获取自定义属性,也可以使用 getAttribute() 获取自定义属性;Firefox 下,只能使用getAttribute() 获取自定义属性。

解决方法: 统一通过 getAttribute()获取自定义属性。

# 11.集合类对象问题

问题说明:IE 下,可以使用 () 或 [] 获取集合类对象;Firefox 下,只能使用 [ ]获取集合类对象。

解决方法: 统一使用 [] 获取集合类对象。

# 12.eval(”idName”)问题

问题说明:IE 下,可以使用 eval(”idName”)getElementById(”idName”) 来取得ididName的 HTML 对象;Firefox 下,只能使用getElementById(”idName”) 来取得 ididName 的 HTML 对象。

解决方法: 统一用 getElementById(”idName”)来取得 ididName 的HTML对象。

# 13.const 问题

问题说明:Firefox 下,可以使用const关键字或var关键字来定义常量;IE 下,只能使用var关键字来定义常量(IE11 解决了)。

解决方法: 统一使用 var 关键字来定义常量。

# 14.input.type 属性问题

问题说明:IE 下input.type 属性为只读;但是 Firefox 下 input.type 属性为读写。

解决办法: 不修改 input.type 属性。如果必须要修改,可以先隐藏原来的input,然后在同样的位置再插入一个新的input元素。

# 15.事件委托方法

问题说明:IE 下,使用 document.body.onload = inject; 其中function inject()在这之前已被实现;在 Firefox 下,使用 document.body.onload = inject();

解决方法: 统一使用 document.body.onload=new Function('inject()'); 或者document.body.onload = function()

# 16.对象宽高赋值问题

问题说明:FireFox 中类似 obj.style.height = imgObj.height的语句无效。

解决方法: 统一使用obj.style.height = imgObj.height + ‘px';

[注] innerHTML 同时被 ie、firefox 等浏览器支持,其他的,如 outerHTML 等只被 ie 支持,最好不用。

# react 浏览器的兼容问题

默认情况下,生成的项目支持所有现代浏览器。 如果你的项目想支持 Internet Explorer 9 , 10 和 11 ,那么需要 polyfills,可自行百度安装使用。

# 检测对象中属性

你想使用 document.querySelector()来选择一个 id,并且让它能兼容 IE6 浏览器,但是在 IE6 浏览器中这个函数是不存在的,那么使用这个操作符来检测这个函数是否存在就显得非常的有用

//if in
if ("querySelector" in document) {
  document.querySelector("#id");
} else {
  document.getElementById("id");
}
1
2
3
4
5
6

# 参考

https://segmentfault.com/a/1190000015722419