深刻理解DOM事件机制系列第二篇——事件处理程序

前面的话

  事件处理程序又叫事件侦听器,实际上就是事件的绑定函数。事件发生时会执行函数中相应代码。事件处理程序有HTML事件处理程序、DOM0级事件处理程序、DOM2级事件处理程序和IE事件处理程序四类,下面将详细介绍该部份内容javascript

 

HTML事件处理程序

  某个元素支持的每种事件,均可以使用一个与相应事件处理程序同名的HTML特性来指定。这个特性的值应该是可以执行的javascript代码html

  在事件处理程序函数内部,this值等于事件的目标元素java

<div id="box" style="height:30px;width:200px;background-color:pink;"onclick = "this.innerHTML+= '1';"></div>

  在HTML中定义的事件处理程序也能够调用在页面其余地方定义的脚本web

<div id="box" style="height:30px;width:200px;background-color:pink;"onclick = "test()"></div>
<script>
    function test(){box.innerHTML+= '1';}    
</script>

  HTML事件处理程序会建立一个封装着元素属性值的函数。这个函数中有一个局部变量event,也就是事件对象。经过event变量,能够直接访问事件对象,不用本身定义它,也不用从函数的参数列表中获取chrome

<div id="box" style="height:30px;width:200px;background-color:pink;"onclick = "this.innerHTML+= event.type;"></div>

  在事件处理程序函数内部,能够像访问局部变量同样访问document及该元素自己的成员。如此一来,事件处理程序要访问本身的属性就简单多了编程

<button id="box" value="test" style="height:30px;width:200px;background-color:pink;"onclick = "this.innerHTML+= value;"></button>

【扩展】浏览器

  下列这种状况输出的是空字符串'',若是与预想结果不一致,请移步至此函数

<script>
var value=123;
</script>
<button style="height:30px;width:200px;background-color:pink;"onclick = "this.innerHTML+= value;"></button>

缺点this

【1】时差问题spa

  由于用户可能会有HTML元素一出如今页面上时就触发相应的事件,但当时的事件处理程序有可能尚不具有执行条件,就会报错

<button style="height:30px;width:200px;background-color:pink;"onclick = "this.innerHTML+= val;"></button>
<script src="http://www.qq.com/test.js"></script>
<script>
var val=123;
</script>

【2】耦合问题

   客户端编程的通用风格是保持HTML内容和javaScript行为分离,因此应该避免使用HTML事件处理程序属性,由于这些属性直接混合了javascript和HTML,且不易扩展

 

DOM0级事件处理程序

  经过javascript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。这种为事件处理程序赋值的方法是在第四代Web浏览器中出现的,并且至今仍然为全部现代浏览器所支持。缘由一是简单,二是具备跨浏览器的优点

  每一个元素都有本身的事件处理程序属性,这些属性一般所有小写,将这种属性的值设置为一个函数,就能够指定事件处理程序

  [注意]以DOM0级方式添加的事件处理程序会在事件流的冒泡阶段被处理

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<script>
box.onclick = function(){this.innerHTML += '1';}    
</script>    

  能够经过将事件处理程序属性设置为null来删除事件处理程序

box.onclick = null;

缺点

  DOM0级事件处理程序的缺点是围绕着每一个事件目标对于每种事件类型只能添加一个事件处理程序

 

DOM2级事件处理程序

  DOM2级事件处理程序定义了两个方法用于处理指定和删除事件处理程序的操做:addEventListener()和removeEventListener()

  全部DOM节点中都包含这两个方法,而且它们都接受3个参数:要处理的事件名、做为事件处理程序的函数和一个布尔值。最后的布尔值参数若是是true,表示在捕获阶段调用事件处理程序;若是是false,表示在冒泡阶段调用事件处理程序。若最后的布尔值不填写,则和false效果同样

  [注意]IE8-浏览器不支持DOM2级事件处理程序

  使用DOM2级事件处理程序的好处是能够添加多个事件处理程序,并按照他们添加的顺序触发

  如下代码以1-2的顺序输出

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<script>
box.addEventListener('click',function(){this.innerHTML += '1'},false);
box.addEventListener('click',function(){this.innerHTML += '2'},false);    
</script>    

  如下代码以2-1的顺序输出

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<script>
setTimeout(function(){
box.addEventListener('click',function(){this.innerHTML += '1'},false);    
},16);
box.addEventListener('click',function(){this.innerHTML += '2'},false);    
</script>

参数

  若是但愿向监听函数传递参数,能够用匿名函数包装一下监听函数

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<script>
box.addEventListener("click",function(){
    test('123');
},false);
function test(x){box.innerHTML += x;}
</script>

移除

  经过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除,移除时传入的参数与添加处理程序时使用的参数相同。这意味着,addEventListener()添加的匿名函数将没法移除  

  如下无效

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<script>
box.addEventListener("click",function(){
    this.innerHTML += '1'
},false);
box.removeEventListener('click',function(){
    this.innerHTML += '1'
},false);    
</script>

  如下有效

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<script>
var handle = function(){this.innerHTML += '1'};
box.addEventListener("click",handle,false);
box.removeEventListener('click',handle,false);    
</script>

IE事件处理程序

  IE实现了与DOM中相似的两个方法:attachEvent()和detachEvent()。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。因为IE8-浏览器只支持事件冒泡,因此经过attachEvent()添加的事件处理程序都会被添加到事件冒泡阶段

  attachEvent()方法的第一个参数是"onclick",而非DOM的addEventListener()方法中的"click"

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<script>
box.attachEvent('onclick',function(){this.innerHTML += '1';});
</script>

   [注意]attachEvent()方法只冒泡到document,且IE10-浏览器支持

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<button id="reset">还原</button>
<script>
//IE10-浏览器返回div body html document
//其余浏览器报错
reset.onclick = function(){history.go();}
box.attachEvent('onclick',function(){box.innerHTML += 'div\n';});
document.body.attachEvent('onclick',function(){box.innerHTML += 'body\n';});
document.documentElement.attachEvent('onclick',function(){box.innerHTML += 'html\n';});
document.attachEvent('onclick',function(){box.innerHTML += 'document\n';});
window.attachEvent('onclick',function(){box.innerHTML += 'window\n';});
</script>    

this

  与其余三个事件处理程序不一样,IE事件处理程序的this指向window,而非被绑定事件的元素

<!-- <div> -->
<div id="box" style="height:100px;width:300px;background-color:pink;"
onclick = "console.log(this)"></div>
<div id="box" style="height:100px;width:300px;background-color:pink;"></div>
<script>
box.onclick= function(){
    console.log(this);//<div>
}
</script>
<div id="box" style="height:100px;width:300px;background-color:pink;"></div>
<script>
box.addEventListener('click',function(){
    console.log(this);//<div>
});
</script>
<div id="box" style="height:100px;width:300px;background-color:pink;"></div>
<script>
box.attachEvent('onclick',function(){
    console.log(this);//window
});
</script>

顺序

  使用attachEvent()方法添加的事件处理程序的触发顺序是有区别的。IE九、10浏览器是按正序执行的,而IE8-浏览器则是按倒序执行的  

<div id="box" style="height:30px;width:100px;background-color:pink;"></div>
<script>
box.attachEvent('onclick',function(){
    box.innerHTML += '1';
});
box.attachEvent('onclick',function(){
    box.innerHTML += '2';
});
</script>

移除

  使用attachEvent()添加的事件能够经过detachEvent()来移除,条件是必须提供相同的参数。与DOM方法同样,这也意味着添加的匿名函数将不能被移除。不过,只要可以将对相同函数的引用传给detachEvent(),就能够移除相应的事件处理程序  

  如下无效

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<script>
box.attachEvent("onclick",function(){
    box.innerHTML += '1'
},false);
box.detachEvent('onclick',function(){
    box.innerHTML += '1'
},false);    
</script>

  如下有效

<div id="box" style="height:30px;width:200px;background-color:pink;"></div>
<script>
var handle = function(){box.innerHTML += '1'};
box.attachEvent("onclick",handle,false);
box.detachEvent('onclick',handle,false);    
</script>    

 

总结

  因为IE8-浏览器不支持addEventListener()方法,因此须要配合attachEvent()方法来实现全浏览器的事件绑定兼容写法。同时,因为attachEvent()方法中的this指向window,因此须要对this进行显式修改

function addEvent(target,type,handler){
    if(target.addEventListener){
        target.addEventListener(type,handler,false);
    }else{
        target.attachEvent('on'+type,function(event){
            return handler.call(target,event);
        });
    }
}

调用顺序

  若是浏览器同时出现这四种事件处理程序,那么它们的调用顺序在各浏览器中表现并不一致 

<div id="box" style="height:100px;width:100px;background:pink;" onclick = "this.innerHTML +='html\n'"></div>
<script>
if(box.addEventListener){
    box.addEventListener('click',function(){this.innerHTML += 'DOM2级\n'})
}    
if(box.attachEvent){
    box.attachEvent('onclick',function(){box.innerHTML +='IE\n'})
}
box.onclick = function(){
    this.innerHTML += 'DOM0级\n';
}
</script>

【相同点】

  若是同时出现HTML事件处理程序和DOM0级事件处理程序,DOM0级会覆盖HTML事件处理程序

【不一样点】

  chrome/opera/safari等webkit内核的浏览器会按照事件处理程序出现的顺序来排列,因此结果为:DOM2级 DOM0级

  firefox浏览器和IE浏览器会将DOM0级事件优先调用

  因此firefox和IE11浏览器结果为:DOM0级 DOM2级

  IE九、10浏览器结果为:DOM0级 DOM2级 IE

  IE8-浏览器结果为:DOM0级 IE

相关文章
相关标签/搜索