JavaScript里面DOM事件有三个阶段:捕获、目标和冒泡。(低版本的IE不支持捕获事件)。

事件流描述的是从页面接收事件的顺序,IE事件流是事件冒泡流;Netscape事件流是事件捕获流。事件冒泡是指事件开始时由最具体的元素(即DOM中嵌套最深的那个节点)接收,然后逐级向上,直到文档顶部。

<div id = "div"> 
    <span id="span"> 
        <a id="aTag">事件测试</a> 
    </span> 
</div> 

JS代码如下:

document.getElementById("aTag").addEventListener('click',aTag); 
document.getElementById("span").addEventListener('click',span); 
document.getElementById("div").addEventListener('click',div); 
function aTag(e) { 
    alert("点击的是a标签"); 
} 
function span(e) { 
    alert("点击的是span标签"); 
} 
function div(e) { 
    alert("点击的是div标签"); 
} 

当点击”事件测试“文字时,click事件会按照如下顺序执行:

点击的是a标签--->点击的是span标签--->点击的是div标签。所有的现代浏览器都支持事件冒泡。

事件捕获:跟事件冒泡正好相反,事件流是从最外层逐级向内传播。

上面的js代码改成这样:

document.getElementById("div").addEventListener('click',div,true); 
document.getElementById("aTag").addEventListener('click',aTag,true); 
document.getElementById("span").addEventListener('click',span,true);
addEventListener函数的第三个参数设置为true(默认为false),即为捕获事件。

当点击”事件测试“文字时,click事件会按照如下顺序执行:

点击的是div标签--->点击的是span标签--->点击的是a标签。

 

DOM事件流

JavaScript上可以在DOM对象上直接注册事件(DOM0级):

document.getElementById('test').onclick = function(e){}

 

这就注册了一个onclick事件。事件被触发时,会传人一个默认参数:e,表示事件对象,通过e,我们会获取到许多有用的信息,例如:点击的坐标,具体触发该事件的DOM元素等,e.target和e.pageX等。事件触发时,this就是指该事件在哪个dom对象上触发。可以debug时查看e和this里具体有哪些信息。

这种注册事件方式,每个DOM元素只能注册一次,再次注册时,后面注册的事件就会覆盖前面的,那么,事件解除就非常简单了,只要再次注册,使得值为null就可以了。

var btn = document.getElementById("test");
btn.onclick = function(e){do something!};
btn.onclick = function(e){do something2!};
btn.onclick = null;//解除绑定

 DOM2级事件定义了两个方法,用于处理指定和删除事件处理程序的操作;addEventListener()和removeEventListener(),所有的DOM节点都包含这两个函数,它们有三个参数第一个参数为事件类型例如:click,mouseover等;第二个参数是事件函数;第三个参数是布尔值,为true表示捕获事件,为false表示冒泡事件。

使用DOM2级添加事件处理程序的一个好处就是可以添加多个事件处理程序,例如:

var btn = document.getElementById("btn"); 
btn.addEventListener('click',function(e){ 
    alert(this.id); 
},false); 
btn.addEventListener('click',function(e){ 
    alert("我是来测试的"); 
},false); 

执行一次点击操作,将会弹出两次对话框。一般情况下我们这么写:

btn.addEventListener('click',handler,false); 
function handler(e){ 
   alert(this.id); 
} 

删除:btn.removeEventListener(‘click’,handler);

下面我们来看看IE下的事件处理,IE下有类似的两个方法:attachEvent()和detachEvent()两个方法,这两个方法只接受两个参数,第一个事件类型,第二个处理函数。由于IE8之前只支持冒泡,所有使用attach()函数添加的事件处理函数会被添加到事件的冒泡阶段。

btn.attachEvent('onclick',handler); 
function handler(e){ 
    alert(this); // window 
}

在使用attachEvent()方法的情况下,事件处理程序在全局作用域下运行,其中的this等于window,且和addEventListener()一样,attachEvent()也可以注册多个事件。

下面我们就可以自己写一个跨浏览器的事件处理程序:

var EventUntil = {
      addEventHandler : function(element,eventtype,handler){
          if(element.addEventListener){
                element.addEventLister(eventtype,handler,false);
          }else if(element.attachEvent){
                element.attachEvent('on'+evevttype,handler);
          }else{
                element['on'+eventtype]=handler;
          }
       },
       removeEventHandler: function(element,eventtype,handler){ 
        if(element.removeEventListener) { 
                    element.removeEventListener(eventtype,handler,false); 
        }else if(element.detachEvent) { 
                    element.detachEvent("on"+eventtype,handler); 
        }else { 
            element["on" +eventtype] = null; 
        } 
    }    
}        

测试:

var btn = document.getElementById('btn');
function handler(e){
    console.log('ok!');
}
EventUntil.addEventHandler(btn,'click',handler);

两种浏览器下都打印出ok!如果需要移除click事件,那么EventUntil.removeEventHandler(btn,'click',handler);

 

完整的跨浏览器事件对象:

var EventUtil = { 
    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; 
        } 
    }, 
    getEvent: function(event) { 
        return event ? event : window.event; 
    }, 
    getTarget: function(event) { 
        return event.target || event.srcElement; 
    }, 
    preventDefault: function(event){ 
        if(event.preventDefault) { 
            event.preventDefault(); 
        }else { 
            event.returnValue = false; 
        } 
    }, 
    stopPropagation: function(event) { 
        if(event.stopPropagation) { 
            event.stopPropagation(); 
        }else { 
            event.cancelBubble = true; 
        } 
    } 
};

 

posted on 2016-03-09 09:22  tse_tung  阅读(115)  评论(0)    收藏  举报