一、浏览器判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var isIE = /*@cc_on!@*/!1;
var isIE = !!document.all; //这个比较容易记,document.all是IE独有的
var isIE678 = !-[1,]; //本来是判断IE最短的语句,但是IE9+之后变为了false,现在可以用来区分IE678与非IE678(因为IE9已经慢慢向W3C靠拢了)
var isIE6 = isIE && !window.XMLHttpRequest; //XMLHttpRequest是所有现代浏览器(IE7+、Fi6refox、Chrome、Safari 以及 Opera)内建的对象,IE6不存在
 
/* cQuery下的使用方法 */
if(cQuery.browser.isIE){
    //IE
}else{
    //非IE
};
//更多浏览器
cQuery.browser = {
    isOpera:false,
    isIE:false,
    isIE6:false,
    isIE7:false,
    isIE8:false,
    isIE9:false,
    isFirefox:false,
    isFirefox2:false,
    isFirefox3:false,
    isFirefox4:false,
    isChrome:false,
    isSafari:false,
    isIPhone:false,
    isIPad:false,
    isIPadUCWeb:false
}

二、Dom兼容性

1.childNodes节点数问题

childNodes 属性返回包含被选节点的子节点的 NodeList。语法是elementNode.childNodes

1
2
3
4
5
6
7
8
<div id="Box">
    <p>1</p>
    <p>2</p>
    <p>3</p>
</div>
<script>
alert(document.getElementById('Box').childNodes.length)
</script>

这个结果在IE6、7、8下是3,在IE9+和非IE浏览器下是7,IE 会忽略节点之间生成的空白文本节点(比如换行字符),而 Mozilla 不这么做,它会将空白文本节点也做为一个节点。因此,在上面的例子中,输出是不同的。如要循环子节点可使用下面的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
var childs = document.getElementById('Box').childNodes;
for(var i=0,l=childs.length; i<l; i++){
    if(childs[i].nodeName != '#text'){
        //操作节点
    }
}
//如果子节点结构不复杂
var childs = document.getElementById('Box').getElementsByTagName('p');
for(var i=0,l=childs.length; i<l; i++){
    //操作节点
}
//cQuery下
var childs = $('#Box>p');

2.获取页面滚动条当前高度

1
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

document.documentElement.scrollTop在IE、FF下有效,但在chrome下却是0,需要使用document.body.scrollTop来获取。

我们可以用这个来算出某个元素相对于整个页面左上角的距离:

1
var top = elem.getBoundingClientRect().top + (document.documentElement.scrollTop || document.body.scrollTop); //elem.getBoundingClientRect()可以得到元素相对于窗口左上角的坐标值

三、CSS兼容性

1.currentStyle

elem.style 获取的只是内联样式,即style属性中的值。要获取样式表中的样式需要通过elem.currentStyle, elem.currentStyle可获取外部(使用<link>)和内部(使用<style>)样式表以及内联style属性中的样式。

elem.currentStyle仅IE和opera支持,FF、chrome等可通过window.getComputedStyle(elem, null)方法获取。

1
2
3
var currentStyle = element.currentStyle || window.getComputedStyle(element, null);
var margeLeft = currentStyle.margeLeft;
var width = currentStyle.width;

PS:这里单词分割不以”-“为分隔符,而是除第一个单词外其他单词首字母大写。

四、事件

1.event和事件源

在IE中event作为window对象的一个属性可以直接使用,但是在Firefox中却使用了W3C的模型,它是通过传参的方法来传播事件的,也就是说你需要为你的函数提供一个事件响应的接口。在使用事件委托的时候,通过事件源获取来判断事件到底来自哪个元素,但是,在IE下,event对象有srcElement属性,但是没有target属性;Firefox下,even对象有target属性,但是没有srcElement属性。 

1
2
3
4
function handler(e){
    e = e || window.event;
    var target = e.srcElement || e.target;
}

2.事件监听

在事件监听处理方面,IE提供了attachEvent和detachEvent两个接口,而Firefox提供的是addEventListener和removeEventListener,attachEvent和addEventListener用来绑定事件,detachEvent和removeEventListener用来解除绑定,同时Firefox下,事件处理函数中的this指向被监听元素本身,而在IE下则不然,IE默认指向window。

另外在IE678下当对同一元素多次绑定事件时,函数触发的顺序与绑定顺序相反,而IE9和Firefox两者顺序相同,为了保持一致我们可以封装下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function addEvent(oTarget, sEventType, fnHandler) {
    if(!oTarget){return;}
    oTarget.listeners = oTarget.listeners || {};
    var listeners = oTarget.listeners[sEventType] = oTarget.listeners[sEventType] || [];
    listeners.push(fnHandler);
    if(!listeners["_handler"]){
        listeners["_handler"] = function(e){
            var e = e || window.event;
            for(var i = 0,fn;fn = listeners[i++];){
                if(fn.call(oTarget,e) === false){
                    e.preventDefault ? e.stopPropagation() : e.cancelBubble = true;
                    e.preventDefault ? e.preventDefault() : e.returnValue = false;
                    return false;
                }
            }
        }
        oTarget.addEventListener ? oTarget.addEventListener(sEventType, listeners["_handler"], false) : oTarget.attachEvent('on' + sEventType, listeners["_handler"]);
    }
}
function removeEvent(oTarget, sEventType, fnHandler) {
    if(oTarget.listeners && oTarget.listeners[sEventType]){
        var listeners = oTarget.listeners[sEventType];
        for(var i = listeners.length-1;i >= 0 && fnHandler;i--){
            if(listeners[i] == fnHandler){
                listeners.splice(i,1);
            }
        }
        if((!listeners.length || !fnHandler) && listeners["_handler"]){
            oTarget.removeEventListener ? oTarget.removeEventListener(sEventType, listeners["_handler"], false) : oTarget.detachEvent('on' + sEventType, listeners["_handler"]);
            delete oTarget.listeners[sEventType];
        }
    }
}
 
//调用方式
addEvent(document.getElementById('ID'), 'click', function(){alert('do click!')});
//cQuery调用方式
$('#id').bind('click', function(){alert('do click!')});

3.event相关属性和方法

1
2
3
4
5
6
7
8
function handler(e){
    e = e || window.event;
    e.preventDefault ? e.stopPropagation() : e.cancelBubble = true; //阻止事件冒泡
    e.preventDefault ? e.preventDefault() : e.returnValue = false;  //阻止事件源默认事件
 
    /*cQuery下可使用stop()方法*/
    e.stop();
}

tab作为tab点击时我们不想执行页面跳转动作时怎么破?IE提供了returnValue属性,如果设置了该属性,它的值比事件句柄的返回值优先级高,把这个属性设置为 fasle,可以取消发生事件的源元素的默认动作。而非IE时可使用preventDefault()方法。

当a标签的父元素上也绑定了事件但我们不想执行时怎么破?IE提供了cancelBubble属性,如果想阻止事件传播到包容对象,必须把该属性设为 true,即阻止事件冒泡。非IE下可使用stopPropagation()方法。

发表评论

电子邮件地址不会被公开。 必填项已用*标注