经过Javascript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。
每一个元素都有本身的事件处理程序属性,这些属性一般所有小写,例如onclick。将这种属性的值设置为一个函数,就能够指定事件处理程序。javascript
var btn = document.getElementById('myBtn'); // 添加事件处理程序 btn.onclick = function () { alert( this );//为DOM元素btn }; // 移除事件处理程序 btn.onclick = null;
优势:1.简单2.具备跨浏览器的优点
缺点:在代码运行以前不会指定事件处理程序,所以这些代码在页面中位于按钮后面,就有可能在一段时间怎么点击都没反应,用户体验变差。html
定义了两个方法,用于处理指定和删除事件处理程序的操做:addEventListener()和removeEventListener()。三个参数,1.要处理的事件名。2.做为事件处理程序的函数3.一个布尔值。最后这个布尔值为true,表示在捕获阶段调用事件处理程序,false表示在冒泡阶段调用事件处理程序。html5
// 添加多个事件处理程序 var btn = document.getElementById('myBtn'); btn.addEventListener('click',function (){ alert( this );// 为DOM元素btn },false ); btn.addEventListener('click',function () { alert('Hello World'); },false); // 移除事件处理程序 btn.removeEventListener('click',function () { // 匿名函数没法被移除,移除失败 },false); // 改写 var handler = function () { alert(this.id); }; btn.addEventListener('click',handler,false); // 再次移除事件处理程序 btn.removeEventListener('click',handler,false);// 移除成功
这两个事件处理程序会按照添加他们的顺序触发。大多数状况,都是将事件处理程序添加到事件流的冒泡阶段,这样能够最大限度的兼容各类版本的浏览器。java
优势: 一个元素能够添加多个事件处理程序
缺点: IE8及如下浏览器不支持DOM2级事件处理程序。(包括IE8)chrome
定义了两个方法,与上相似:attachEvent(),detachEvent()。这两个方法接收相同的两个参数:事件处理程序名称和事件处理程序函数。因为IE8以及更早版本的浏览器只支持事件冒泡,因此经过detachEvent()添加的事件处理程序会被添加到冒泡阶段。浏览器
var btn = document.getElementById('myBtn'); btn.attachEvent('onclick', function(){ alert( this );// window }); btn.attachEvent('onclick', funciton(){ alert("HELLO, WORLD"); });
点击按钮,这两个事件处理程序的触发顺序与上述恰好相反。不是按照添加事件处理程序的顺序触发,恰好相反。app
优势:一个元素能够添加多个事件处理程序
缺点:只支持IE。函数
var EventUtil = { addHandler : function ( ele, type, handler ) { if ( ele.addEventListener ) { ele.addEventListener( type, handler, false ); } else if ( ele.attachEvent ) { ele.attachEvent( 'on' + type, handler ); } else { ele['on' + type] = handler } }, removeHandler: function ( ele, type, handler ) { if ( ele.removeEventListener ) { ele.removeEventListener( type, handler, false ); } else if ( ele.detachEvent ) { ele.detachEvent( 'on' + type, handler ); } else { ele[ 'on' + type ] = null; } } }
兼容DOM的浏览器会将一个event对象传入到事件处理程序中。不管指定事件处理程序时使用什么方法(DOM0级或DOM2)级,都会传入event对象。event对象包含与建立它的特定事件有关的属性和方法。触发的事件类型不同,可用的属性和方法也不同。不过,全部事件都有下表列出的成员性能
| 属性/方法 | 类型 | 说明
| ---------—--- | ------------- | ------------
| bubbles
| cancebles
| currentTarget
| defaultPrevented
| detail
| evnetPhase
| preventDefault
| stopImmediatePropagation()
| stopPropagation()
| target
| trusted
| type
| viewthis
1.currentTarget与target
target :事件的目标对象
currenTarget : 其当前事件处理程序正在处理事件的那个元素
var btn = document.getElementById('myBtn'); btn.onclick = function ( e ) { console.log( this === e.currentTarget );// true console.log( this === e.target );// true }; document.body.onclick = function ( e ) { console.log( this === e.currentTarget );// true console.log( this === e.target );// false };
点击按钮,结果如上。
2.preventDefault()与cancelable
cancelable :只读属性,代表是否能够取消事件的默认行为,值为true即可以,反之不行。
preventDefault :阻止特定事件的默认行为。例如,连接的默认行为就是在被单击时会导航到其href特性指定的URL。
var link = document.getElementById( 'myLink' ); link.onclick = function ( e ) { // 阻止默认行为 e.preventDefault();// 只有cancelable设置为true的事件,才可使用 }
3.stopPropagation()与eventPhase
stopPropagation() : 取消事件进一步捕获或冒泡,若是bubbles为true,则可使用这个方法
eventPhase : 调用事件处理程序的阶段:1.表示捕获阶段2.表示'处于目标阶段'3.表示冒泡阶段。
var btn = document.getElementById('myBtn'); document.body.addEventListener( 'click', function ( e ) { alert( e.eventPhase ); }, true );// 1 btn.addEventListener( 'click',function ( e ) { alert( e.eventPhase ); }, false );// 2 document.body.addEventListener( 'click', function ( e ) { alert( e.eventPhase ); }, false );// 3
点击btn按钮弹出1,2,3。
var btn = document.getElementById('myBtn'); document.body.addEventListener( 'click', function ( e ) { alert( e.eventPhase );// 1 }, true ); btn.addEventListener( 'click',function ( e ) { // 阻止进一步的事件冒泡 e.stopPropagation(); alert( e.eventPhase );// 2 }, false ); document.body.addEventListener( 'click', function ( e ) { alert( e.eventPhase );// 点击按钮时,事件处理程序被阻止,无反应 }, false );
点击btn按钮弹出1,2。
var btn = document.getElementById('myBtn'); document.body.addEventListener( 'click', function ( e ) { // 阻止进一步的事件冒泡 e.stopPropagation(); alert( e.eventPhase );// 1 }, true ); btn.addEventListener( 'click',function ( e ) { alert( e.eventPhase );// 点击按钮时,事件处理程序被阻止,无反应 }, false ); document.body.addEventListener( 'click', function ( e ) { alert( e.eventPhase );// 点击按钮时,事件处理程序被阻止,无反应 }, false );
点击btn按钮弹出1。
访问IE中的event对象有几种不一样的方式,取决于指定事件处理程序的方法。IE的event对象一样也包含与建立它的事件相关的属性和方法。与DOM中的event对象同样,这些属性和方法也会由于事件类型的不一样而不一样,但全部事件对象都会包含下表所列的属性和方法。
| 属性/方法 | 类型 | 说明
| ---------—--- | ------------- | ------------
| cancelBubble
| returnValue
| srcElement
| type
1.srcElement
事件的目标(与DOM中的target属性相同)
var btn = document.getElementById('myBtn'); btn.onclick = function () { alert( window.event.srcElement === this )// true }; btn.attachEvent('onclick', function (e) { alert( e.srcElement === this ) // false, IE事件处理程序绑定this的值为window });
2.returnValue
默认值为true,但将其设置为false就能够取消事件的默认行为(与DOM中的preventDefault()做用相同)
var link = document.getElementById( 'myLink' ); link.onclick = function () { // 阻止默认行为 window.event.returnValue = false; }
与DOM不一样的是,在此没有办法肯定事件是否能被取消。
3.cancelBubble
默认值为false,但将其设置为true就能够取消事件冒泡(与DOM中的stopPropagation()做用相同)
var btn = document.getElementById('myBtn'); btn.onclick = function () { alert( 'Clicked' ); window.event.cancelBubble = true; }; document.body.onclick = function () { alert( 'Body Clicked' ) };
要访问IE中event对象有几种不一样的方式,取决于指定事件处理程序的方法。在使用DOM0级方法添加事件处理程序时,event对象做为window对象的一个属性存在。使用IE事件处理程序,event对象能够经过window对象进行访问,同时也会被当作参数传递。
var EventUtil = { getEvent: function( event ){ return event ? event : window.event } }
DOM3级事件模块在DOM2级事件模块基础上从新定义了这些事件,也添加了一些新事件。包括IE9在内的全部主流浏览器都支持DOM2级事件。IE9也支持DOM3级事件。
DOMContentLoaded :
能够为document和window添加相应的事件处理程序(尽管这个事件会冒泡到window,但它的目标其实是document)。
DOMContentLoaded中的event对象
不会提供额外的信息(其target属性是document)
兼容性:IE9+,Fifrefox,Chrome,Safari3.1+,Opera9+。
hashchange :
必需要把hashchange事件处理程添加给window对象
,而后URL参数列表只要变化就会调用它。
此时的event对象
应该额外包含两个属性:oldURL和newURL。这两个属性分别保存着参数列表变化先后的完整URL。
兼容性:IE8+,firefox3.6+,Safari5+,Chrome,Opera10.6+。在这些浏览器中只有Firefox6+,chrome和Opera支持oldURL和newURL属性。为此,最好是使用location对象来肯定当前的参数列表。
keydown(任意键),keypress(字符键), keyup
发生keypress事件意味着按下的键会影响到屏幕中文本的显示。在全部浏览器中,按下可以插入或者删除字符的键都会触发keypress事件。
全部元素都支持以上三个事件,但只有在用户经过文本框输入文本时才最经常使用到
触发顺序:在用户按下了一个字符键时,keydown-->keypress-->keyup。在用户按下的是一个非字符键,keydown-->keyup。
event对象
shiftKey,ctrlKey,altKey和metaKey属性。
在发生keydown和keyup事件时,event对象
的keyCode属性会包含一个键码。
兼容性:IE不支持metaKey
Working With the Keyboard
mousedown,mouseup
click,dbclick
全部元素都支持鼠标事件。
触发顺序:mousedown-->mouseup-->click-->mousedown-->mouseup-->click--dbclick。在IE8以及以前版本,有一个小bug,会跳过第二个mousedown和click
event对象:
clientX和clientY:表示事件发生时,鼠标指针在视口中的水平和垂直坐标
PageX和PageY:表示鼠标光标在页面中的位置,所以坐标是从页面自己,而非视口的左边和顶边计算的。
screenX和screenY:能够肯定鼠标事件发生时,鼠标指针相对于整个屏幕的坐标信息。
shiftKey,ctrlKey,altKey和metaKey属性。
mousedown和mouseup事件,还包括一个button属性:表示按下或释放的按钮DOM的button属性可能有以下3个值,0表示主鼠标按钮,1表示中间的鼠标按钮,2表示次鼠标按钮。
兼容性:
IE8以及更早版本不支持事件对象上的页面坐标,不过使用客户区坐标和滚动信息能够计算出来。
IE8以及更早版本不支持metaKey属性。
touchstart
在javascript中,添加到页面上的事件处理程序数量将直接关系到页面的总体运行性能。
1.每一个函数(事件处理程序)都是对象,都会占用内存。内存中的对象越多,性能就越差。
2.必须事先指定全部 事件处理程序而致使的DOM访问次数,会延迟整个页面的交互就绪时间。
3.每当将 事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的Javascript代码之间就会创建一个链接。这种链接越多,页面执行起来越慢。
<div id="love-wrapper"> <div id="love-l">L</div> <div id="love-o">O</div> <div id="love-v">V</div> <div id="love-e">E</div> </div> var l = document.getElementById( 'love-l' ); var o = document.getElementById( 'love-o' ); var v = document.getElementById( 'love-v' ); var e = document.getElementById( 'love-e' ); l.addEventListener('click', function () { alert(' L ') }, false); o.addEventListener('click', function () { alert( 'O' ) }, false); v.addEventListener('click', function () { alert( 'V' ) }, false); e.addEventListener('click', function () { alert( 'E' ) }, false);
在上面的示例中,为每一个元素的点击事件都绑定了不一样事件处理程序。
取得了4个DOM元素。==>DOM访问次数为4次
添加了4个事件处里程序。==>内存中的对象多增长了4个
相应的事件处理程序与指定元素链接了4次==》链接数4
若是页面复杂,那么就会有数不清的代码用于添加事件处理程序。影响页面性能。
对事件处理程序过多问题的解决方案就是事件委托。
事件委托利用了事件冒泡,只指定一个事件处理程序,就能够管理
某一类型(例如:点击事件)的全部事件。
若是可行的话,能够考虑为document对象添加一个事件处理程序,用以处理页面上特定类型的事件。有点以下
document对象很快就能够访问,并且能够在页面生命周期中的任什么时候点上为它添加事件处理程序(无需等待load和DOMContentLoaded事件)。换句话说,只要可点击的元素呈如今页面上,就能够当即具有适当的功能
在页面中设置事件处理程序所需的时间更少。只添加一个事件处理程序所需的DOM引用更少,所花的时间更少。 整个页面所占得内存空间更少
var love = document.getElementById( 'love-wrapper' ); love.addEventListener('click', function ( e ) { switch ( e.target.id ) { case 'love-l' : alert('L'); break; case 'love-o' : alert('O'); break; case 'love-v' : alert('V'); break; case 'love-e' : alert('E'); break; } },false)
在上面的示例中
取得了1个DOM元素。==>DOM访问次数减小到了1次
添加了1个事件处理程序。==>内存中的对象只增长了1个
相应的事件处理程序与指定元素链接了4次==>链接数1
实现了和上一个例子中同样的效果。可是却有效的控制了DOM访问次数,事件处理程序的添加个数,以及DOM元素与相应的事件处理程序的链接次数。
利用事件委托咱们能够有效的控制相应的事件处理程序与指定元素的链接次数。另外,在不须要的时候移除事件处理程序,也是解决这个问题的一种方案。内存中留有那些过期不用的"空事件处理程序,也是形成Web应用程序内存和性能问题的主要缘由"。
有两种状况可能致使上述问题
带有事件处理程序的 指定元素 经过DOM操做被删除了,页面中的某一部分被替换了,致使带有事件处理程序的 指定元素 被删除了。
卸载页面的时候。
第一种状况:本质上来说都是一种状况,就是带有事件处理程序的 指定元素被删除了,可是其事件处理程序仍然和 指定元素保持着引用关系,致使其事件处理程序没法被当作垃圾回收。(尤为是IE)会作出这种处理
<div id="myDiv"> <div id="myBtn"></div> </div> var handler = function () { // 删除指定元素 document.getElementById( 'myDiv' ).removeChild(); } var btn = document.getElementById('myBtn'); btn.addEventListener('click', handler, false);
点击按钮时,按钮被删除,可是其事件处理程序却还和其保持了引用关系,致使内存增长。所以在知道 指定元素可能被删除的状况下,先解除他们之间的引用关系。以下
<div id="myDiv"> <div id="myBtn"></div> </div> var handler = function () { // 解除链接引用关系 btn.removeEventListener( 'click', handler, false ); // 删除指定元素 document.getElementById( 'myDiv' ).removeChild(); } var btn = document.getElementById('myBtn'); btn.addEventListener('click', handler, false);
这样经过解除引用链接关系,也能够提高页面性能。
第二种状况:IE8及更早浏览器在这种状况下仍然是问题最多的浏览器。若是在页面卸载以前,没有清理干净事件处理程序,那它们就会滞留在事件处理程序中。
通常来讲,最好的作法是在页面卸载以前,先经过unload事件处理程序移除全部事件处理程序。