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; } } };
浙公网安备 33010602011771号