总结DOM中和IE中事件对象的属性和方法;
封装一个通用的事件处理类;
理解事件代理
在此备忘,方便查询使用 O(∩_∩)O
事件对象
DOM中的事件对象(常用的)
type属性 用于获取事件类型
event.type
target属性 用于获取事件目标
event.target
你也可以获取事件目标的节点名称
event.target.nodeName
stopPropagation()方法 用于阻止事件冒泡
event.stopPropagation()
preventDefault()方法 阻止事件的默认行为
event.preventDefault()
tip:默认行为是什么?
例如 a标签
<a href=”#”>超链接</a>
的默认行为就是跳转。
阻止a的默认行为就是阻止a跳转。
IE中的事件对象(常用的)
type属性 用于获取事件类型
event.type
srcElement属性 用于获取事件目标
event.srcElement
cancelBubble属性 用于阻止事件冒泡
设置为true表示阻止冒泡
event.cancelBubble=true
设置为false表示不阻止冒泡
event.cancelBubble=false
returnValue属性 阻止事件的默认行为
默认为true
设置为false表示阻止事件的默认行为
event.returnValue=false
关于event:
IE8之前的浏览器event要这样获取:
window.event
因此我们的event这样获取便可兼容所有浏览器:
event = event || window.event
跨浏览器事件处理程序
通用事件处理文件
此封装了一个事件处理程序函数,此函数应用了能力检测来满足不同浏览器。
将此函数放到一个js文件里,需要绑定事件时引用此文件,可处理所有的事件绑定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| 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; }, getType:function(event){ return event.type; }, getElement: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; } } }
|
用法
引用包含上述代码的文件,我们现在可以使用它来给我们的程序添加事件了~
例:我们来给一个按钮绑定一个弹出“hello world”的事件
HTML:
1
| <input type="button" value="按钮" id="button">
|
JS:
1 2 3 4 5 6 7 8
| var btn=document.getElementById("button"); function showMes(){ alert("hello world"); } eventUtil.addHandler(btn,"click",showMes); eventUtil.removeHandler(btn,"click",showMes);
|
测试一下,chrome和IE都没有问题,你可以试一下更低的版本,都OK。
事件代理
什么是事件代理?
当我们需要对很多元素添加事件的时候,可以通过将事件添加到它们的父节点而将事件委托给父节点来触发处理函数。
例:假设有一个 UL 的父节点,包含了很多个 Li 的子节点
1 2 3 4 5 6 7 8
| <ul id="parent-list"> <li id="post-1">Item 1</li> <li id="post-2">Item 2</li> <li id="post-3">Item 3</li> <li id="post-4">Item 4</li> <li id="post-5">Item 5</li> <li id="post-6">Item 6</li> </ul>
|
当我们的鼠标移到Li上的时候,需要获取此Li的相关信息并飘出悬浮窗以显示详细信息,或者当某个Li被点击的时候需要触发相应的处理事件。
我们通常的写法,是为每个Li都添加一些类似onMouseOver或者onClick之类的事件监听。
1 2 3 4 5 6 7 8 9 10 11 12
| function addListeners4Li(liNode){ liNode.onclick = function clickHandler(){...}; liNode.onmouseover = function mouseOverHandler(){...} } window.onload = function(){ var ulNode = document.getElementById("parent-list"); var liNodes = ulNode.getElementByTagName("Li"); for(var i=0, l = liNodes.length; i < l; i++){ addListeners4Li(liNodes[i]); } }
|
如果这个UL中的Li子元素会频繁地添加或者删除,我们就需要在每次添加Li的时候都调用这个addListeners4Li方法来为每个Li节点添加事件处理函数。这就添加的复杂度和出错的可能性。
更简单的方法是使用事件代理机制,当事件被抛到更上层的父节点的时候,我们通过检查事件的目标对象(target)来判断并获取事件源Li。下面的代码可以完成我们想要的效果:
1 2 3 4 5 6 7 8
| document.getElementById("parent-list").addEventListener("click",function(e) { if(e.target && e.target.nodeName.toUpperCase == "LI") { console.log("List item ",e.target.id.replace("post-")," was clicked!"); } });
|
为父节点添加一个click事件,当子节点被点击的时候,click事件会从子节点开始向上冒泡。父节点捕获到事件之后,通过判断e.target.nodeName来判断是否为我们需要处理的节点。并且通过e.target拿到了被点击的Li节点。从而可以获取到相应的信息,并作处理。
在JavaScript编程中使用代理
上面介绍的是对DOM事件处理时,利用浏览器冒泡机制为DOM元素添加事件代理。其实在纯JS编程中,我们也可以使用这样的编程模式,来创建代理对象来操作目标对象。这里引用司徒正美相关文章中的一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| var delegate = function(client, clientMethod) { return function() { return clientMethod.apply(client, arguments); } } var ClassA = function() { var _color = "red"; return { getColor: function() { console.log("Color: " + _color); }, setColor: function(color) { _color = color; } }; }; var a = new ClassA(); a.getColor(); a.setColor("green"); a.getColor(); console.log("执行代理!"); var d = delegate(a, a.setColor); d("blue"); console.log("执行完毕!"); a.getColor();
|
上面的例子中,通过调用delegate()函数创建的代理函数d来操作对a的修改。这种方式尽管是使用了apply(call也可以)来实现了调用对象的转移,但是从编程模式上实现了对某些对象的隐藏,可以保护这些对象不被随便访问和修改。
用js函数的apply方法来制定执行作用域,可以解决很多问题。
jQuery中delegate函数
1 2 3 4
| $("#link-list").delegate("a", "click", function(){ console.log("you clicked a link!",$(this)); });
|
jQuery的delegate的方法需要三个参数,一个选择器,一个时间名称,和事件处理函数。
优点
1.管理的函数变少了。不需要为每个元素都添加监听函数。对于同一个父节点下面类似的子元素,可以通过委托给父元素的监听函数来处理事件。
2.可以方便地动态添加和修改元素,不需要因为元素的改动而修改事件绑定。
3.JavaScript和DOM节点之间的关联变少了,这样也就减少了因循环引用而带来的内存泄漏发生的概率。
参考文献:
[1] JavaScript高级程序设计(第3版)- 事件
[2] JavaScript事件代理和委托(Delegation)