javascript中有两种事件模型:DOM0,DOM2。而对于这两种的时间模型,我一直不是很是的清楚,如今经过网上查阅资料终于明白了一些。javascript
一. DOM0级事件模型html
DOM0级事件模型是早期的事件模型,全部的浏览器都是支持的,并且其实现也是比较简单。代码以下:java
<p id = 'click'>click me</p> <script> document.getElementById('click').onclick = function(event){ alert(event.target); } </script>
这种事件模型就是直接在dom对象上注册事件名称,这段代码就是在p标签上注册了一个onclick事件,在这个事件函数内部输出点击的目标。而解除事件则更加简单,就是将null复制给事件函数,以下:浏览器
document.getElementById('click'_).onclick = null;
由此咱们能够知道dom0中,一个dom对象只能注册一个同类型的函数,由于注册多个同类型的函数的话,就会发生覆盖,以前注册的函数就会无效。dom
var click = document.getElementById('click');
click.onclick = function(){
alert('you click the first function');
};
click.onclick = function(){
alert('you click the second function')
}
在这段代码中,咱们为dom对象注册了两个onclick函数,可是结果是只执行了第二个注册的函数,前面所注册的函数被覆盖了。函数
二. DOM2级事件模型spa
1. 事件捕获和事件冒泡(capture,bubble)code
首先,IE8及如下是不支持这种事件模型的。事件捕获和事件冒泡的机制以下图:htm
如上图所示,123表明事件捕获,4567表明事件冒泡。首先咱们使用下面的代码:对象
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'> <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div> </div>
假设咱们点击了ID为inner的div,那么此时的事件流程就是,首先执行捕获阶段:document-html-body-div(outer)。而后执行冒泡阶段:div(inner)-div(outer)-body-html-document。
2. DOM2级的注册事件和解除事件
在DOM2级中使用addEventListener和removeEventListener来注册和解除事件(IE8及以前版本不支持)。这种函数较之以前的方法好处是一个dom对象能够注册多个相同类型的事件,不会发生事件的覆盖,会依次的执行各个事件函数。
addEventListener('事件名称','事件回调','捕获/冒泡')。示例以下:
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'> <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div> </div> <script> var click = document.getElementById('inner'); click.addEventListener('click',function(){ alert('click one'); },false); click.addEventListener('click',function(){ alert('click two'); },false); </script>
首先咱们要知道addEventListenr的第一个参数是事件名称,与DOM0级不一样的是没有”on“,另外第三个参数表明捕获仍是冒泡,true表明捕获事件,false表明冒泡事件。
而在这段代码中,咱们为inner的div注册了两个click事件函数,结果是浏览器会依次执行这两个函数。
下面咱们演示如何使用事件流的发生机制。
<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'> <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div> </div> <script> var click = document.getElementById('inner'); var clickouter = document.getElementById('outer'); click.addEventListener('click',function(){ alert('inner show'); },true); clickouter.addEventListener('click',function(){ alert('outer show'); },true); </script>
这段代码,咱们使用了捕获事件,因为inner是嵌套在outer中的,因此咱们知道当使用捕获的时候outer是应该首先捕获到这个事件的,其次inner才能捕获到这个事件。那么结果就是outer首先执行,其次是inner执行。
那么我把outer的执行时机改成冒泡的阶段呢?
alickouter.addEventListener('click',function(){
alert('outer show');
},false);
这种状况下,就是先执行inner后执行outer了。同理咱们把两者的事件执行时机都改成冒泡阶段的话,依旧是先执行inner后执行outer。那么还有个问题,就是若是咱们把inner注册两个click事件,一个是在捕获阶段,另外一个是在冒泡阶段,也就是说把addEventListenter的第三个参数分别设置为false和true,那么执行的顺序又是怎样的呢。
<script> var click = document.getElementById('inner'); var clickouter = document.getElementById('outer'); click.addEventListener('click',function(){ alert('capture show'); },true); click.addEventListener('click',function(){ alert('bubble show'); },false); </script>
这种状况下首先这些的是capture show,其次是bubble show。可是这种结果是与注册的顺序有关系的,先注册就先执行。由于咱们在看事件捕获和事件冒泡示意图,发现最后具体的dom对象是只有一个的。
那么 若是咱们给outer和inner都注册了click事件可是我不但愿outer执行怎么办呢?这个时候咱们就须要用到stopPropagation函数了,这个函数是用来阻止冒泡,言下之意是让事件再也不继续冒泡下去,这样接下来注册一样类型事件的dom对象就不会执行了。好比在自制下拉框的时候,咱们点击浏览器的其余位置,咱们须要下拉框的options隐藏,这时咱们就要用到stopPropagation了。以下:
<script> var click = document.getElementById('inner'); var clickouter = document.getElementById('outer'); click.addEventListener('click',function(event){ alert('inner show'); event.stopPropagation(); },false); clickouter.addEventListener('click',function(){ alert('outer show'); },false); </script>
正常的状况下,咱们在不添加stopPropagation函数时,首先应该执行inner,而后执行outer,可是当咱们在inner的事件函数中添加了stopPropagation函数以后,执行完inner的事件函数以后,就不会在执行outer的事件函数了,也能够理解为事件冒泡到inner以后就消失了,所以也就不会在执行接下来的事件函数了。
因为事件捕获阶段没有能够阻止事件的函数,因此通常都是设置为事件冒泡。