浅析JavaScript Event
Event Types
JavaScript的事件类型,一般来说可以分为以下几几大类:
- UI Events:例如window.onload, windown.onunload等events;
- 鼠标点击事件:例如onmousedown, onmouseup, onmouse, onmouseover, onmousemove, click, dbclick等等;
- 键盘点击事件:例如onkeypress, onkeydown, onkeyup
- 表单事件:例如onsubmit
- 元素聚焦事件:例如onfocus, onblur
Mouse Event
当我们点击鼠标的时候,会触发相对应的鼠标事件,譬如onmousedown, onmouseup, onmousemove, onmouseover, click, dbclick.
event.button可以获取当前用户点击鼠标的位置,1-primary key, 2-secondary key, 3-wheel (IE下面有更多的可能性,1-primary key, 2-secondary key, 3-wheel,4-左右两键同时按下,5-primary + wheel key,6-secondary + wheel key,7-三个按键同时按下)
当我们触发鼠标的双击事件时,实际上发生如下事件: onmousedown > onmouseup > click > onmousedown > onmouseup > click > dbclick (IE下面的情况有点特殊,发生了如下的事件:onmousedown > onmouseup > click > onmousedown > dbclick)
var elem = document.getElementById('elem'); elem.addEventListener('mousedown' function(e) { console.debug('mousedown triggered'); }, false); elem.addEventListener('mouseup' function(e) { console.debug('mouseup triggered'); }, false);
Key Event
当我们敲击键盘上的某一个按键的时候,会触发一个key event,例如keydown, keyup, keypress
var elem = document.getElementById('elem'); elem.addEventListener('keydown', function(e) { consloe.debug('keydown triggered!'); }, false); elem.addEventListener('keyup', function(e) { consloe.debug('keyup triggered!'); }, false); elem.addEventListener('keypress', function(e) { consloe.debug('keypress triggered!'); }, false);
Event Phases
一个事件的触发,从开始到结束,总共经历了Event Capturing > Target Event > Event Bubbling三个过程,为了能够有一个更为直观的理解,请看下面一段简单的HTML代码:
<!DOCTYPE html> <html> <head><title>Event Demo</title></head> <body><div id='msg'>Click Me!</div></body> </html>
当我们点击Click Me!的时候,触发了click事件,整个事件的流程如下图所示:
从上图,我们可以很清楚的看到整个click event事件的流程.
Event Object
当我们触发某个事件的时候,我们可以通过event对象来获取当前所发生事件的一些具体的信息,比如event type, event target, event button等等,不同的浏览器,我们获取event object的方式不同:
- IE浏览器:旧版本的IE浏览器中(IE<9),我们通过window.event来获取当前的event object
- 其他非IE浏览器:当我们触发某一个时间的时候,会将event object作为一个参数传递给当前所触发或者绑定的事件
Binding Events
通常,我们在HTML页面中,是通过为某一个DOM元素绑定特定Javascript事件来实现页面的交互,由于不同的浏览器有不同的实现,我们一般有如下三种绑定事件的方法:
- 最传统的绑定事件的方法是通过如下的形式来绑定:
var elem = document.getElementById('elem'); elem.onclick = function () { console.log('elem is clicked!'); }
这种方法的优势:
- 适用性最广发,基本所有的浏览器都支持这种事件的绑定方法
这种方法的劣势:
- 一个事件只能够绑定一个处理方法
- 只能够处理Event Bubbling Phase
- 在绑定的处理方法中,this指向的是window对象,而并不是当前的操作对象
- 只能通过window.event来获取当前触发的event对象
- IE下的事件绑定方法addEvent(type, handler),具体如下所示:
var elem = document.getElementById('elem'); elem.addEvent('onclick', function() { console.log('elem is clicked!'); });
这种方法的优势:
- 对于某一个事件,可以绑定任意多个处理事件
- 在所绑定的处理事件中,this指向的是当前的操作对象
这种方法的劣势如下:
- 只适用于IE的事件绑定
- Event类型必须以'on' + type的形式传递给addEvent方法
- 只能通过window.event来获取当前的event对象
- 只能够处理event bubbling phase
- 现代标准浏览器的事件绑定方法:addEventListener(type, handler, capturing)
var elem = document.getElementById('elem'); elem.addEventListener('click', function() { console.log('elem is clicked!'); }, false);
这种方法的优势如下:
- 对于同一个触发事件,可以绑定任意多个处理事件
- 可以同时处理capturing/bubbling event phase, attachEventList方法的最后一个参数为一个boolean类型的参数,true表示的是处理event capturing phase, false为event bubbling phase
- 可以轻松获取当前的event object,event object直接以参数的形式传递给绑定的处理方法
- 在绑定的处理方法中,this指向的是当前的操作对象
这种方法的劣势如下:
- IE下面的绑定事件不支持此种操作方法
由于不同的浏览器有不同的具体实现,为了实现对event事件的跨浏览器操作,我们有必要开发一个通用的事件绑定方法,次方法应该最大限度的支持现行的所有浏览器,可以轻松获取当前的event object,可以轻松获取当前的操作对象,以下为一个参考的例子:
var $events = { guid : 1, attachEvent : function (elem, type, handler) { if (!handler._guid) { handler._guid = this.guid++; } if (!elem.events) { elem.events = {}; } var handlers = elem.events[type]; if (!handlers) { handlers = elem.events[type] = {}; if (elem['on' + type]){ handlers[0] = elem['on' + type]; } } handlers[handler._guid] = handler; elem['on' + type] = handleEvent; function handleEvent(e) { var rtnValue = true; e = e || window.event; e = fixEvent(e); var handlers = elem.events[type]; for (var key in handlers) { if (handlers[key](e) === false) { rtnValue = false; } } return rtnValue; }; function fixEvent(e) { e.preventDefautl = fixEvent.preventDefautl; e.stopPropagation = fixEvent.stopPropagation; return e; } fixEvent.stopPropagation = function () { this.returnValue = false; } fixEvent.preventDefautl = function () { this.cancelBubble = true; } }, removeEvent : function (elem, type, handler) { if (elem.events && elem.events[type]) { delete elem.events[type][handler._guid]; } }, };
Remove Events
我们可以通过以下的方法对事件进行解绑:
- 通过传统方法绑定的事件,可以充值绑定对象为null来实现事件的解绑,如下所示:
elem.onclick = null
- 通过IE的addEvent(type, handler)方法绑定的事件,可以通过removeEvent(type, handler)来解绑事件,如下所示:
elem.removeEvent('onclick', handler);
- 现代标准浏览器,可以通过removeEvent(type, handler)的方式来解绑事件,如下所示:
elem.removeEvent('click', handler);