1 事件流
事件冒泡:当一个元素接收到事件的时候,会把他接收到的所有传播到他的父级,一直传播到window。阻止冒泡:在当前要阻止冒泡的事件函数中调用 event.cancleBubble=true;现代的浏览器中默认使用的是事件冒泡机制,由于老版本不支持事件捕获,所以很少有人使用事件捕获。因此建议使用事件冒泡。
2 事件处理程序
在DOM中,用于处理指定和删除事件的处理程序的操作:addEventListener()和removeEventListener().在两种方法中,接收三个参数:要处理的事件名、事件处理的函数,选用何种阶段调用事件处理程序。其中第三个参数如果为true的话,则表示在捕获阶段调用事件处理程序,为flase的话,则表明在冒泡的阶段调用事件处理函数。如果为同一个元素添加了多个事件处理程序,那么会按照添加的顺序进行触发。
两种方法中,其是相生相对的,即通过第一种方法添加的事件处理必须用第二种方法来解除;同时要注意在移除时,所传入的函数必须与添加时所传入的函数相同,这也意味着添加方法中,如果添加匿名函数的化,那么将难以移除。(IE9,Firefox,Safari,Chrome和Opera支持DOM2级事件处理程序)
在IE中,存在着相对应的attachEvent()和detachEvent(),同时注意在这两种方法中接收:事件处理程序名称和事件处理函数。同时由于IE的特殊性,所以其一般默认添加到冒泡的阶段调用事件处理函数。注意如果为同一元素添加多个事件处理程序,那么会以相反的顺序触发。注意:支持IE事件处理程序的浏览器只有IE和Opera。
为了处理好跨浏览器的方式处理事件,所以使用一个名叫EventUtil的对象。
var EventUtil = { addHandler: function(element, type, handle){ if(element.addEventListener){ element.addEventListener(type, handle, false) } else if (element.attchEvent){ element.attachEvent("on" + type, handle) //为了在IE8及更早版本中运行,事件类型要加上“on”前缀。 } else{ element["on" + type] = handle; //该方法为DOM0使用的方法,一般不会执行该方法。 } }, removeHandler: function(element, type, handle){ if(element.removeEventListener){ element.removeEventListener(type, handle, false) } else if (element.detachEvent){ element.attachEvent("on" + type, handle) } else{ element["on" + type] = null; } } }
3 事件对象
该内容不熟,先跳过。
4 事件类型
该内容太复杂,先略过。
5 内存和性能
由于每个函数都是对象,会占用内存,;如果对象过多,那么性能就会越差。其中造成性能过差的原因之一就是事件处理程序过多,所以事件委托机制就产生了。
事件委托机制利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。以下面为例:
//这是传统的做法var item1 = document.getElementById(‘goSome‘); var item2 = document.getElementById(‘doSome‘); var item3 = document.getElementById(‘sayHi‘); EventUtil.addHandler(item1,‘click‘,function(e){ location.href = ‘http://www.weibo.com‘; }) EventUtil.addHandler(item2,‘click‘,function(e){ document.title = ‘I changed the title‘; }) EventUtil.addHandler(item3,‘click‘,function(e){ alert(‘hi‘); })
//这是事件委托机制下的做法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.cancelBubbles = true; } }, getRelatedTarget: function (event) { if (event.relatedTarger) { return event.relatedTarget; } else if (event.toElement) { return event.toElement; } else if (event.fromElement) { return event.fromElement; } else { return null; } } }; var list = document.getElementById(‘myLinks‘); EventUtil.addHandler(list,‘click‘,function(e){ event = EventUtil.getEvent(e); var target = EventUtil.getTarget(event); switch(target.id){ case "goSome": location.href = ‘http://www.weibo.com‘; break; case "doSome": document.title = ‘I changed the title‘; break; case "sayHi": alert(‘hi‘); break; } });
在上个代码中,只为ul元素添加一个点击事件。在ul元素下的li中,其会冒泡,所以li的点击都会被这个函数所处理。由于其只取得一个DOM元素,所以占用的内存更少,所有用到按钮的事件都适合采用事件委托技术。
新的做法与传统的做法有几个优点:
(1)document对象很快可以访问。而且可以在页面生命周期的任何时点上围棋添加事件处理程序(不需要DOMContentLoaded或load事件)。即如果可以点击的元素呈现在页面上,便可以具备相应的功能。
(2)在页面中设置事件处理程序所需的时间更少。
(3)提升整体性能。
能够采用事件委托技术的事情包括click、mousedown、mouseup、keydown、keyup和keypress。虽然mouseover和mouseout事件也冒泡,但是经常要计算其元素的位置,所以不建议使用。
为了提高整体性能,除了可以使用事件委托机制以外,还可以在不需要的时候移除事件处理程序。
该套方法还是不太熟悉,再跳过。
6 模拟事件