JavaScript 事件

来源:互联网 发布:数据网关介绍 编辑:程序博客网 时间:2024/06/15 00:58

事件处理程序

DOM0 级事件处理程序

DOM0级事件处理程序是将一个函数赋值给一个事件处理程序属性,使用这种方式比较简单,而且具有跨浏览器的优势;每个事件仅支持一个事件处理程序;
每个元素都有自己的事件处理程序,DOM0级方法指定的事件处理程序可以认为是元素的方法,因此可以通过this获得对当前元素的引用;
这种方式添加的事件处理程序会在事件流的冒泡阶段被处理;

可以通过将其设为null解除事件绑定;btn.onclick = null;

所有浏览器均支持DOM0级事件处理程序;


DOM2级事件处理程序

DOM2级事件定义了addEventListener()和removeEventListener(),第三个参数为false表示冒泡阶段调用事件处理程序;所有的DOM节点都具有这两个方法。使用removeEventListener()移除事件处理程序时必须要与建立时传入相同的参数,addEventListener()添加的匿名函数是无法移除的;

相比于DOM0级事件处理程序,DOM2可以为同一事件添加多个事件处理程序,一般会按照它们添加的顺序触发;


IE事件处理程序

IE中使用了attachEvent()和detachEvent()实现了与DOM中类似的功能,这两个函数均接受两个参数;事件前需要加”on”。IE8及更低版本仅支持事件冒泡,故attachEvent()添加的事件都会添加到冒泡阶段;

IE中使用这些方法与使用DOM0级方法的区别是事件处理程序的作用域不同:IE中attachEvent()作用域为全局作用域,而DOM0级方法的事件处理程序作用域为目标元素作用域;
同样,attachEvent()也支持为一个事件绑定多个事件处理程序,但是事件触发是以绑定的相反顺序执行;


跨浏览器事件处理程序

/** * 跨浏览器的的事件处理程序 * @type {Object} */var EventUtil = {    addHandler: function (element, type, handler) {         if (element.addEventListener) {     // DOM2级            element.addEventListener(type, handler, false);        } else if (element.attachEvent) {       // IE             element.attachEvent('on' + type, handler);        } else {        // DOM0级            element['on' + type] = handler;        }       },    removeHandler: function (element, type, handler) {        if (element.removeEventListener) {            element.removeEventListener(type, handler,)        } else if (element.detachEvent) {            element.detachEvent('on' + type, handler);        } else {            element['on' + type] = null;        }    }}


事件对象

触发DOM事件时,会生成一个包含着事件相关信息(事件名称/ 事件类型等)的事件对象event();

DOM中的事件对象

无论以DOM0级还是DOM2级指定事件处理程序,都会传入event对象;
通过HTML特定指定的事件处理程序中,变量event保存着event对象;

DOM中事件对象event具有以下属性:
type:String,事件类型;
bubbles:布尔值,事件是否支持冒泡;
cancelable: 布尔值,是否支持取消事件的默认行为;
eventPhase: Integer, 1捕获阶段,2目标阶段,3冒泡阶段;

事件处理程序内部,对象this始终等于currentTarget的值,this === event.currentTarget,target只包含事件的实际目标;

当事件处理程序直接制定给目标元素时,this/ currentTarget/ target三者相等;一个事件处理程序处理多个事件时可以使用switch(event.type);

对cancelable属性为true的事件中, preventDefault()方法可以用于阻止事件默认行为,比如阻止链接跳转;

stopPropagation()方法用于立即停止事件在DOM层级中的传播,取消进一步的捕获和冒泡;

event对象只在事件处理程序执行期间存在,之后该对象就会被销毁;


IE的事件对象

根据指定事件处理程序的方法,要访问IE中的event对象有不同的方式;
1、使用DOM0级添加事件处理程序时,event对象是window对象的一个属性;
2、使用attachEvent()添加事件处理程序,那么就有一个event对象传入事件处理程序函数中;

这里写图片描述

这里写图片描述

3、HTML特性指定的事件处理程序可以通过一个名为event的变量访问event对象;

IE中的事件对象属性:
cancelBubble:boolean, 表示是否取消冒泡, 默认false;(对应DOM中的stopPropagation())
returnValue: boolean,表示阻止事件默认行为,默认为true;(对应DOM中的preventDefault())
srcElement:Element,表示事件目标;
type:String,表示事件类型;

由于IE中存在多种调用方式,因此事件处理程序的作用域也会随之变化;因此this并不会始终等于事件目标;event.srcElement更加可靠;


跨浏览器的事件对象

/** * 跨浏览器的的事件处理程序 * @type {Object} */var EventUtil = {    getEvent: function (event) {    // 获取对象        return event ? event : window.event;    },    getTarget: funciton (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;        }    },    addHandler: function (element, type, handler) {         ...    },    removeHandler: function (element, type, handler) {        ...    }}   

事件类型

DOM3级事件模块是在DOM2级事件模块的基础上新增了一些事件;IE9+等主流浏览器均支持DOM2级事件,IE9也支持DOM3级事件;

DOM3级规范定义的事件类型:
UI事件、焦点事件、鼠标事件、滚轮事件、键盘事件、文本事件(文档中输入文本时触发)、合成事件(为输入法编辑器输入字符时触发)、变动事件(底层DOM结构变化时触发);

1、UI事件:
load(页面完全加载后在window上触发,图片加载完毕在<img>元素上触发,所有框架加载完毕在框架上触发);
unload (应用较多的情况是清除引用,避免内存泄漏)
abort(嵌入内容未加载完或用户地址下载过程时,在<object>元素上触发)
error (JS脚本错误、无法加载图像、无法加载嵌入内容、无法加载框架时触发)
select(选择文本框(<input><textarea>)中的字符时触发);
resize
scroll

2、焦点事件
blur, focus, focusin(支持冒泡), focusout(blur的通用版);

foucs和blur不支持冒泡,但仍可以在捕获阶段贞听到它们;

3、鼠标和滚轮事件
mousedown、mouseup、click、dbclick、mouseenter、mouseleave、mousemove、mouseout(鼠标指针离开被选元素或者其任何子元素时都会触发,包括被选元素与子元素间的切换)、mouseover;

出了mouseenter和mouseleave外,其他鼠标事件都支持冒泡;

鼠标事件发生的同时可以获取事件对象发生的位置信息clientX和clientY(鼠标指针在视口中的水平坐标和垂直坐标);
页面坐标通过事件对象的pageX和pageY属性;无滚动情况下其与clientX和clientY相等;

屏幕坐标位置event.screenX和event.screenY,

一些按键可能会影响鼠标事件的响应:Shift/ Ctrl/ Alt/ Meta(windows键、cmd键),对应四个修改键状态:shiftKey/ ctrlKey/ altKey/ metaKey,这些属性都是布尔值,按下则对应为true;IE9+等都支持这四个修改键,但IE8不支持metaKey;

相关元素:mouseover,mouseout事件触发时涉及到的元素不只是目标元素;mouseover的目标元素为获取光标的元素,而相关元素是失去光标的元素;mouseout的目标元素是失去光标的元素,而相关元素是获得光标的元素; DOM可以通过event.relatedTarget获取相关元素信息,对于mouseover和mouseout有值,而对其他事件属性为null,IE8-不支持event.relatedTarget,可以通过fromElement(mouseover)和toElement(mouseout)属性保存相关元素;

getRelatedTarget: function (event) {    if (event.relatedTarget) {  // DOM相关对象        return event.relatedTarget;    } else if (event.toElement) {       // IE mouseout        return event.toElement;    } else if (event.fromElement) {     // IE mouseover        return event.fromElement;    } else {    // mouseover和mouseout之外的其他事件        return null;    }}

鼠标按钮:mouseover和mouseout事件的event对象存在一个表示按下或释放的按钮的button属性;DOM的button属性:0-主鼠标按钮、1-鼠标中间按钮、2-次鼠标按钮;IE8及之前的浏览器button属性有所不同,定义了8个值,可以将其转为DOM方式;

所有浏览器都支持mousewheel,其还有一个对应属性wheelData属性,为120的倍数,正数表示顺时针,负数表示逆时针;

4、键盘和文本事件

3个键盘事件:keypress/ keyup/ keydown;(按键按住时会重复触发keypress和keydown)

键码:DOM和IE均支持event.keyCode;
字符编码:IE9+浏览器的event对象均支持charCode属性,event.charCode; IE8及之前的版本和Opera则使用event.keyCode中保存字符的ASCII编码;

5、变动事件
DOMNodeRemoved、DOMNodeInserted、DOMSubstreeModified等被IE9+支持;

6、HTML5事件

contextmenu:自定义上下文菜单,支持冒泡;使用该方法需要阻止浏览器的默认行为;可以使用列表定义菜单,并设置默认visibility为hidden;然后触发contextmenu时改为visible;通过监听onclick事件再次修改visibility为hidden;

// html<div id="listWrapper">    <ul id="list" style="position: absolute;visibility: hidden;background-color: silver;">        <li>HTML</li>        <li>CSS</li>        <li>JS</li>        <li>JAVA</li>    </ul></div>// jsvar wrapper = document.getElementById('listWrapper');var handler = function (event) {    var event = event || window.event;    event.preventDefault();    var menu = document.getElementById('list');    menu.style.left = event.clientX + 'px';    menu.style.top = event.clientY + 'px';    menu.style.visibility = 'visible';}wrapper.addEventListener('contextmenu', handler, false);document.body.addEventListener('click', function (event) {    document.getElementById('list').style.visibility = 'hidden';}, false);

beforeunload:

DOMContentLoaded:DOMContenteLoaded事件则在DOM树构建完成后就触发,可以更早地进行时间响应,不必像window.load对象那样需要等待css、JS、图片等外部资源加载完成才响应事件;
DOMContentLoaded事件需要绑定到document和window对象(该事件的目标元素是document,会冒泡到window);
IE9+、FireFox、Chrome、Safari等都支持该事件;

readystatechange事件: 支持readystatechange事件的每个对象都有一个readyState属性,有5个取值:uninitialized/ loading/ loaded/ interactive/ complete,但不是每个对象都会经历5个状态;

haschange事件:在URL参数列表变化时触发;其必须绑定到window对象上,并且此时会具有两个属性oldURL和newURL;haschange事件被IE8+等浏览器支持,但是两个属性值并被浏览器通用,所以建议使用location获取URL参数列表;

7、触摸与手势事件

触摸事件: touchstart、touchmove(发生时要阻止其默认行为)、touchend(该事件发生后touches集合中没有任何Touch对象)、touchcancel;这些触摸事件是以兼容DOM的方式实现的;
上述触摸事件的event对象具有在鼠标事件中的常见属性:type、bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、ctrlKey、shiftKey、altKey、metaKey;
当然,触摸事件还包含三个跟踪触摸的属性:
A:touches - 当前跟踪的触摸操作的Touch对象的数组;
B:targetTouches - 事件目标的Touch对象的数组;
C:changeTouches - 上次触摸后发生改变的Touch对象的数组;

Touch对象的属性:identifier、target、clientX、clientY、screenX、screenY、pageX、pageY

手势事件: gesturestart、gesturechange、gestureend;


内存和性能

给页面添加事件处理程序会影响页面的整体性能;原因一是每个处理函数都是对象,都会占用内存;并且内存中的对象越多则性能越差;原因二是事先指定的事件处理程序会增加DOM访问次数,从而给页面加载带来延时,影响用户的交互体验;

从事件处理程序角度优化性能的方式主要有事件委托移除事件处理程序

事件委托:该方法基于事件冒泡原理,通过给DOM树中尽可能高的父辈元素添加事件处理程序,从而能够处理某一类型的所有事件;
适合采用事件委托的事件包括:click、mousedown/ mouseup、keydown/ keyup/ keypress.

移除事件处理程序:在不需要使用时及时移除事件处理程序也是提升性能的一种方法;
两种情况可能造成不用的“空事件处理程序”保留在内存中。第一种是使用removeChild()/ replaceChild(),更多是innerHTML进行页面内容替换时,如果替换或者移除元素时没有移除事件处理程序,那么这类事件处理程序很可能无法当做垃圾回收;这种情况需要手动移除事件处理程序; 第二种是在卸载页面前没有清空事件处理程序,这类事件处理程序就会继续滞留在内存中;解决方法是在页面卸载前,通过onUnload事件移除所有事件处理程序;


事件模拟

事件模拟就是使用JavaScript模拟浏览器原生的事件;IE9+等均支持事件模拟;

1、DOM中的事件模拟
在document对象上使用createEvent(string)创建event对象,参数表示事件类型,值可以取为UIEvents/ MouseEvents/ MutationEvents/ HTMLEvents;
接着需要对创建的event对象使用特定事件的相关信息进行初始化;例如模拟鼠标事件时创建的event对象有一个initMouseEvent()的方法用于初始化;
最后使用dispatchEvent(event)方法触发事件,参数为要触发的event对象;之后浏览器就可以相应这些事件;


参考文献
《JavaScript高级程序设计》第三版

原创粉丝点击