摘要:作为事件处理程序的函数一个布尔值。最后这个布尔值为表示在捕获阶段调用事件处理程序,表示在冒泡阶段调用事件处理程序。阻止特定事件的默认行为。
事件处理程序 DOM0级事件处理程序
通过Javascript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。
每个元素都有自己的事件处理程序属性,这些属性通常全部小写,例如onclick。将这种属性的值设置为一个函数,就可以指定事件处理程序。
var btn = document.getElementById("myBtn"); // 添加事件处理程序 btn.onclick = function () { alert( this );//为DOM元素btn }; // 移除事件处理程序 btn.onclick = null;
优点:1.简单2.具有跨浏览器的优势
缺点:在代码运行之前不会指定事件处理程序,因此这些代码在页面中位于按钮后面,就有可能在一段时间怎么点击都没反应,用户体验变差。
定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener()。三个参数,1.要处理的事件名。2.作为事件处理程序的函数3.一个布尔值。最后这个布尔值为true,表示在捕获阶段调用事件处理程序,false表示在冒泡阶段调用事件处理程序。
// 添加多个事件处理程序 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);// 移除成功
这两个事件处理程序会按照添加他们的顺序触发。大多数情况,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度的兼容各种版本的浏览器。
优点: 一个元素可以添加多个事件处理程序
缺点: IE8及以下浏览器不支持DOM2级事件处理程序。(包括IE8)
定义了两个方法,与上类似:attachEvent(),detachEvent()。这两个方法接收相同的两个参数:事件处理程序名称和事件处理程序函数。由于IE8以及更早版本的浏览器只支持事件冒泡,所以通过detachEvent()添加的事件处理程序会被添加到冒泡阶段。
var btn = document.getElementById("myBtn"); btn.attachEvent("onclick", function(){ alert( this );// window }); btn.attachEvent("onclick", funciton(){ alert("HELLO, WORLD"); });
点击按钮,这两个事件处理程序的触发顺序与上述刚好相反。不是按照添加事件处理程序的顺序触发,刚好相反。
优点:一个元素可以添加多个事件处理程序
缺点:只支持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中的事件对象
兼容DOM的浏览器会将一个event对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法(DOM0级或DOM2)级,都会传入event对象。event对象包含与创建它的特定事件有关的属性和方法。触发的事件类型不一样,可用的属性和方法也不一样。不过,所有事件都有下表列出的成员
| 属性/方法 | 类型 | 说明
| ---------—--- | ------------- | ------------
| bubbles
| cancebles
| currentTarget
| defaultPrevented
| detail
| evnetPhase
| preventDefault
| stopImmediatePropagation()
| stopPropagation()
| target
| trusted
| type
| view
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中的事件对象访问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 } }事件类型
HTML5事件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代码之间就会建立一个连接。这种连接越多,页面执行起来越慢。
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);LOVE
在上面的示例中,为每个元素的点击事件都绑定了不同事件处理程序。
取得了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)会做出这种处理
var handler = function () { // 删除指定元素 document.getElementById( "myDiv" ).removeChild(); } var btn = document.getElementById("myBtn"); btn.addEventListener("click", handler, false);
点击按钮时,按钮被删除,但是其事件处理程序却还和其保持了引用关系,导致内存增加。因此在知道 指定元素可能被删除的情况下,先解除他们之间的引用关系。如下
var handler = function () { // 解除连接引用关系 btn.removeEventListener( "click", handler, false ); // 删除指定元素 document.getElementById( "myDiv" ).removeChild(); } var btn = document.getElementById("myBtn"); btn.addEventListener("click", handler, false);
这样通过解除引用连接关系,也可以提升页面性能。
第二种情况:IE8及更早浏览器在这种情况下仍然是问题最多的浏览器。如果在页面卸载之前,没有清理干净事件处理程序,那它们就会滞留在事件处理程序中。
一般来说,最好的做法是在页面卸载之前,先通过unload事件处理程序移除所有事件处理程序。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/78645.html
摘要:标准库中的所有方法都提供非阻塞的异步版本,并接受回调函数,某些方法还具有对应的阻塞方法,其名称以结尾。比较代码阻塞方法同步执行,非阻塞方法异步执行。 阻塞与非阻塞概述 此概述介绍了Node.js中阻塞与非阻塞调用之间的区别,此概述将引用事件循环和libuv,但不需要事先了解这些主题,假设读者对JavaScript语言和Node.js回调模式有基本的了解。 I/O主要指与libuv支持的...
摘要:调用栈是单线程编程语言,意味着它只有单一的调用栈。调用栈是一种数据结构,基本记录了程序运行的位置。举个例子,先来看如下所示的代码当引擎开始执行这段代码时,调用栈将是空的。这正是抛出异常时栈追踪的构造过程这基本上就是异常抛出时调用栈的状态。 原文 How JavaScript works: an overview of the engine, the runtime, and the c...
摘要:调用栈是一种数据结构,它记录了我们在程序中的位置。当从这个函数返回的时候,就会将这个函数从栈顶弹出,这就是调用栈做的事情。而且这不是唯一的问题,一旦你的浏览器开始处理调用栈中的众多任务,它可能会停止响应相当长一段时间。 原文地址: https://blog.sessionstack.com... PS: 好久没写东西了,最近一直在准备写一个自己的博客,最后一些技术方向已经敲定了,又可以...
摘要:调用栈是一种单线程编程语言,这意味着它只有一个调用堆栈。调用栈是一种数据结构,它记录了我们在程序中的位置。而且这不是唯一的问题,一旦你的浏览器开始处理调用栈中的众多任务,它可能会停止响应相当长一段时间。 本文是旨在深入研究JavaScript及其实际工作原理的系列文章中的第一篇:我们认为通过了解JavaScript的构建块以及它们是如何工作的,将能够编写更好的代码和应用程序。我们还将分...
摘要:是如何工作的引擎,运行时以及调用栈的概述原文译者随着变得越来越流行,团队在多个层级都对它进行利用前端,后端,混合应用,嵌入式设备以及更多。这个将会在是如何工作的的第二部分进一步解释。 How JavaScript works: an overview of the engine, the runtime, and the call stack JavaScript是如何工作的:引擎,运...
摘要:如果我们进入一个函数,我们在堆栈的顶部。看看下面的代码当引擎开始执行此代码时,调用堆栈将为空。之后,步骤如下调用堆栈中的每个条目称为堆栈帧。这正是抛出异常时构造堆栈跟踪的方式当异常发生时,它基本上是调用堆栈的状态。 随着JavaScript越来越受欢迎,团队正在利用这个技术栈在多个层次- 前端,后端,混合应用程序,嵌入式设备等等提供支持。 这篇文章旨在成为系列中第一个旨在深入挖掘Jav...
阅读 1967·2021-11-23 10:08
阅读 2308·2021-11-22 15:25
阅读 3255·2021-11-11 16:55
阅读 744·2021-11-04 16:05
阅读 2528·2021-09-10 10:51
阅读 693·2019-08-29 15:38
阅读 1546·2019-08-29 14:11
阅读 3463·2019-08-29 12:42