在原始事件模型中(也有说DOM0级),事件发生后没有传播的概念,没有事件流。监听函数只是元素的一个属性值,通过指定元素的属性值来绑定监听器。
两种方式:
① HTML代码中指定属性值:<input type=”button” onclick=”clickFunction()” />
② 在js代码中指定属性值:document.getElementsById(“element”).onclick = function(){};
优点: 1)所有浏览器都兼容2)速度快
缺点:1)逻辑与显示没有分离;2)相同事件的监听函数只能绑定一个,后注册的会覆盖掉前面的3)无法通过事件的冒泡、委托等机制完成更多事情。
“IE不把该对象传入事件处理函数,由于在任意时刻只会存在一个事件,所以IE把它作为全局对象window的一个属性”。E是将event对象在处理函数中设为window的属性,一旦监听函数执行结束,window.event便被置为null了。IE的事件模型只有两步,先执行元素的监听函数,然后事件沿着父节点一直冒泡到document。
注册事件监听函数的方法attachEvent( "eventType","handler"),其中evetType为事件的类型,如onclick,注意要加‘on’。
解除事件监听函数的方法 detachEvent("eventType","handler" )
此模型是W3C制定的标准模型,既然是标准,那大家都得按这个来,我们现在使用的现代浏览器(指IE6~8除外的浏览器)都已经遵循这个规范。W3C制定的事件模型中,一次事件的发生包含三个过程:
(1)capturing phase:事件捕获阶段。事件被从document一直向下传播到目标元素,在这过程中依次检查经过的节点是否注册了该事件的监听函数(捕获方式),若有则执行。
(2)target phase:事件处理阶段。事件到达目标元素,执行目标元素的事件处理函数(没有传播机制,不论是捕获方式或冒泡方式注册的事件监听函数,按照注册监听函数的先后顺序).
(3)bubbling phase:事件冒泡阶段。事件从目标元素上升一直到达document,同样依次检查经过的节点是否注册了该事件的监听函数(冒泡方式),有则执行。
所有的事件类型都会经历captruing phase但是只有部分事件会经历bubbling phase阶段,例如submit事件就不会被冒泡。
标准的事件监听函数注册:addEventListener("eventType","handler","true|false");其中eventType指事件类型,注意不要加‘on’前缀,与IE下不同。第二个参数是处理函数,第三个即用来指定是否在捕获阶段进行处理,一般设为false与IE保持一致,IE使用冒泡反式处理监听,默认值为 false。相应的解除监听器:removeEventListner("eventType","handler","true!false");
obj.addEventListener("click", func, true); // 捕获方式obj.addEventListener("click", func, false); // 冒泡方式
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div id="parent" style="background-color: red; width: 500px;height: 500px;"> parent <div id="child" style="padding: 25px;background-color: blue; height: 80%"> child (点击child,child作为目标元素,没有传播机制,不论是捕获方式或冒泡方式注册的事件监听函数,按照注册监听函数的先后顺序)<br> 输出结果:<br> parent 捕捉<br> child 冒泡 <br> child 捕捉<br> parent 冒泡<br> </div> </div> <script language="javascript"> var parent = document.getElementById("parent"); var child = document.getElementById("child"); parent.addEventListener("click", function () { console.log("parent 冒泡") }, false); parent.addEventListener("click", function () { console.log("parent 捕捉") }, true); child.addEventListener("click", function () { console.log("child 冒泡") }, false); child.addEventListener("click", function () { console.log("child 捕捉") }, true); </script> </body> </html>
兼顾IE与非IE浏览器的事件监听
//兼顾IE与非IE浏览器的事件监听 var obj = document.getElementById('objId'); if(obj.attachEvent){ //IE obj.attachEvent('onclick',function(){}); }else{ //非IE obj.addEventListener('click',function(){},false); }
自己不想处理,让父节点来处理。运用在监听动态增加的元素。基于冒泡方式实现。
<ul id="list"> <li>列表内容1</li> <li>列表内容2</li> <li>列表内容3</li> <li>列表内容4</li> <li>列表内容5</li></ol> </ul>
不使用委托方式给各个li注册事件
var listArray = document.getElementById('list').childNodes; for(var i=0;i<listArray.length;i++){ listArray[i].addEventListener('click',function({ alert(this.innerText); }); }
当在ul中增加一个li时,必须给该li注册监听函数。这样会导致代码繁琐,同样会给浏览器带来性能的开销。
使用委托方式,委托给ul来处理
//使用委托方式,委托给ul来处理 var list = document.getElementById('list'); olist.addEventListener('click',function(){ alert(event.target.innerText); },false); //冒泡方式
2. Live 、delegate 使用委托方式实现,能够处理动态添加元素的事件监听。live方法将事件监听函数注册到document上面,delegate可以指定将事件监听函数注册到哪个元素上面。
3. bind、on没有使用委托方式实现,不能处理动态添加元素的事件监听。bind内部调用on方法。
4. 另外,element.click(function(){});是作为element.bind(“click”,function(){})简写方式。