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高级程序设计》第三版
- Javascript事件
- javascript 事件
- Javascript 事件
- javascript 事件
- Javascript 事件
- JavaScript 事件 ***
- Javascript事件
- Javascript 事件
- JavaScript 事件
- Javascript 事件
- javascript事件
- javascript事件
- javascript 事件
- javascript事件
- javascript 事件
- JavaScript 事件
- JavaScript事件
- JavaScript 事件
- Ansible实用案例之批量重装mysql
- Csharp基础整理
- quartz学习3:quartz线程管理
- 刷CCF的算法题(第五天)
- 2017年8月20日 星期日
- JavaScript 事件
- 欢迎使用CSDN-markdown编辑器
- CodeChef:Chef and Problems(分块 & 二分)
- smtp邮件协议
- java.nio.Buffer源码解读
- python使用scrapy爬取qq音乐(二)
- Spark基础-Scala模式匹配
- RILD
- python 基础教程系列12.GUI