《JavaScript高级程序设计》| 第十三章:事件

事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用侦听器(或处理程序)来预定事件,以便事件发生时执行相应的代码。

一、事件流

事件流描述的是从页面接收事件的顺序。
IE和Netscape开发团队的具有几乎完全相反的事件流概念。
IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕获流。

1.事件冒泡

事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

2.事件捕获

事件捕获(event capturing),事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。

3.DOM事件流

“DOM2级事件”规定事件流包括:事件捕获阶段、处于目标阶段和时间冒泡阶段。
首先发生的是事件捕获阶段,为截获事件提供机会。染回是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。


二、事件处理程序

事件就是用户或浏览器自身执行的某种动作。诸如clickloadmouseover,都是事件的名字。
而响应某个事件的函数就叫作事件处理程序(事件侦听器)。事件处理程序的名字都是以on开头的,如:onclickonmouseoveronload

1.HTML事件处理程序

某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定。

<input type="button" value="Click me" onclick="alert('Clicked')"/>
<input type="button" value="Click me" onclick="alert(&quot;clicked&quot;)" />
<input type="button" value="Click me" onclick="showMessage()"/>

<script type="text/javascript">
function showMessage(){
	alert("Hello World!");
}
</script>

需要注意的是:如果HTML特性值中时JavaScript代码,则不能在其中使用未经转义的HTML语法字符。
为了避免使用HTML实体,这里使用了单引号。

通过event变量,可以直接访问事件对象。且在函数内部,this值等于事件的目标元素。
且在事件处理程序中的代码在执行时,有权访问全局作用域中的任何代码。

HTML事件处理程序的缺点:

  • 时差问题;
  • 扩展事件处理程序的作用域链在不同浏览器中会导致不同的结果;
  • HTML与JavaScript代码紧密耦合;

2.DOM0级事件处理程序

将一个函数赋值给一个事件处理程序属性。

var btn = document.getElementById("myBtn");
btn.onclick = function(){
	alert(this.id);		//"myBtn"
}

3.DOM2级事件处理程序

用于处理指定和删除事件处理程序的操作:

  • addEventListener()removeEventListener()
  • 所有DOM节点都包含这俩个参数方法。
  • 它们都接受三个参数:要处理的事件名、作为事件处理程序的函数、布尔值;
  • 布尔值参数为true,表示在捕获阶段调用事件处理程序;为false,表示在冒泡阶段调用事件处理程序。
  • 可以添加多个事件处理程序。
var btn = document.getElementById("myBtn");
btn.addEventListener("click",function(){
	alert(this.id);
},false);
btn.addEventListener("click",function(){
	alert("Hello World!");
},false);

移除事件处理程序:

  • 传入removeEventListener()中的参数必须与addEventListener()中的一致。
var btn = document.getElementById("myBtn");
var handler = function(){
	alert(this.id);
};

btn.addEventListener("click",handler,false);

btn.removeEventListener("click",handler,false);

大多数情况下,都是将时间处理程序添加到事件流的冒泡阶段,这样可以最大限度的兼容各种浏览器。

4.IE事件处理程序

IE中实现了与DOM中类似的俩个方法:

  • attachEvent()detachEvent()
  • 这俩个方法都接受相同的俩个参数:事件处理程序名称、事件处理程序函数;
  • 添加的事件处理程序会被添加到冒泡阶段;
  • 可以添加多个事件,以添加的相反顺序触发;

attachEvent()的第一个参数是onclick;而非DOM的addEventListener()方法中的click;
②使用DOM0级方法的情况下,时间处理程序会在其所属元素的作用域内运行;在使用attachEvent()方法的情况下,时间处理程序会在全局作用域中运行,因此this等于window

5.跨浏览器的时间处理程序

为了以跨浏览器的方式处理事件,开发人员会使用能够隔离浏览器差异的JavaScript库,还有一些开发人员会开发最合适的事件处理方法。


三、事件对象

在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。

1.DOM中的事件对象

兼容DOM的浏览器会将一个event对象传入到事件处理程序中。
event对象包含与创建它的特定事件有关的属性和方法。

  • 在事件处理程序内部,对象this始终等于currentTarget属性(时间处理程序当前正在处理事件的那个元素)的值;而target属性(事件的目标)则只包含事件的实际目标。
  • 需要通过一个函数处理多个事件时,可以使用type属性(被触发的事件类型);
  • 要阻止特定事件的默认行为,可以使用preventDefault()方法;
  • 只有cancelable属性(是否可以取消事件的默认行为)设置为true的事件,才可以使用prevnetDefault()方法。
  • stopPropagation()方法用于立即停止事件在DOM层次中的传播,即取消进一步的事件捕获或冒泡。
  • 事件对象的eventPhase属性可以确定事件当前正处于事件流的哪个阶段:1表示捕获阶段;2表示"处于目标";3表示冒泡阶段;
//使用type属性处理多个事件
var btn = document.getElementById("myBtn");
var handler = function(event){
	switch(event.type){
		case "click":
			alert("clicked");
			break;
		case "mouseover":
			event.target.style.backgroundColor = "red";
			break;
		case "mouseover":
			event.target.style.backgroundColor = "";
			break;
	}
};

btn.onclick = handler;
btn.onmouserover = handler;
btn.onmouseout = handler;

//使用preventDefault()方法阻止特定事件的默认行为
var link = document.getElementById("myLink");
link.onclick = function(event){
	event.preventDefault();
};

//使用stopPropagation()方法取消进一步的事件捕获或冒泡
var btn = document.getElementById("myBtn");
btn.onclick = function(event){
	alert("Clicked");
	event.stopPropagation();
};

document.body.onclick = function(event){
	alert("Body clicked");
};

2.IE中的事件对象

与访问DOM中的event对象不同,要访问IE中的event对象有几种不同的方式,取决于指定时间处理程序的方法。
在使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在。

var btn = document.getElementById("myBtn");
btn.onclick = function(){
	var event = window.event;
	alert(event.type);		//"click"
}

IE中的事件对象也会包含一些属性和方法:

  • cancelBubble:默认为false,但将其设置为true就可以取消事件冒泡;
  • returnValue:默认值为true,但将其设置为false就可以取消事件的默认行为;
  • srcElement:事件的目标
  • type:被触发的事件的类型

因为事件处理程序的作用域是根据指定它的方式来确定的,所以不能认为this会始终等于事件目标。

3.跨浏览器的事件对象


四、事件类型

1.UI事件

DOMActivateloadunloaderrorabortselectresizescroll

load事件

当页面完全加载后(包括图片、JavaScript文件、CSS文件等外部资源),就会触发window上面的load事件。

unload事件

当文档被完全卸载后触发。只要用户从一个页面切换到另一个页面,就会发生unload事件。而利用这个事件最多的情况是清除引用,以避免内存泄漏。

resize事件

当浏览器窗口被调整到一个新的高度或宽度时,就会触发resize事件。
浏览器最小化或最大化也会触发resizi事件。

scroll事件

2.焦点事件

blurDOMFocusInDOMFocusOutfocusfocusinfocusout

3.鼠标与滚轮事件

clickdbclickmousedownmouseentermouseleavemousemovemouseoutmouseovermouseupmousewheel

4.键盘与文本事件

keydownkeypresskeyuptextInput

5.复合事件

compositionstartcompositionupdatecompositionend

6.变动事件

DOMSubtreeModifiedDOMNodeInsertedDOMNodeRemovedDOMNodeInsertIntoDocumentDOMNodeRemoveFromDocumentDOMAttrModifiedDOMCharacterDataModified

7.HTML5事件

①contextmenu事件

用以表示何时应该显示上下文菜单,该事件是冒泡的。
通常使用contextmenu事件来显示自定义的上下文菜单,而使用onclick事件处理程序来隐藏该菜单。

②beforeunload事件

这个事件会在浏览器卸载页面之前触发,可以通过它来取消卸载并继续使用原有页面。

③DOMContentLoaded事件

DOMContentLoaded事件在形成完整的DOM树之后会触发,不理会图像、JavaScript文件、CSS文件或其他资源是否已经下载完毕。
load事件不同,DOMContentLoaded支持在页面下载的早期添加事件处理程序,这也就意味着用户能够尽早地用于页面进行互动。

④readystatechange事件

该事件的目的是提供与文档或元素的加载状态有关的信息。
支持readystatechange事件的每个对象都有一个readystate属性,属性值如下:

  • uninitialized(未初始化):对象存在但尚未初始化;
  • loading(正在加载):对象正在加载数据;
  • loaded(加载完毕):对象加载数据完成;
  • interactive(交互):可以操作对象,但还没有完全加载;
  • complete(完成):对象已经加载完毕;

并非所有对象都会经历readyState的这几个阶段。即如果某个阶段不适用某个对象,则该对象完全可能跳过该阶段;并没有规定哪个阶段适用于哪个对象。

⑤pageshow和pagehide事件

“往返缓存”(back-forward cache,bfcache),该特性可以在用户使用浏览器的“后退”和前进按钮时加快页面的转换速度。这个缓存不仅保存着页面数据,还保存了DOM和JavaScript的状态;实际上是将整个页面保存在了内存里。
如果页面位于bfcache中,那么再次打开该页面就不会触发load事件。

  • pageshow:该事件在页面显示后触发,无论页面是否来自bfcache;该事件的event事件包含一个名为persisted的布尔值属性。如果该页面被保存在bfcache中,则为true;否则为false
  • pagehide:该事件会在浏览器卸载页面时触发,而且是在unload事件之前触发。

以上俩个事件的目标都是document,但其事件处理程序必须要添加到window对象中。

⑥hashchange事件

hashchange事件处理程序必须添加给window对象,然后URL参数列表只要有变化就会调用它。
此时的event对象额外包含俩个属性:oldURLnewURL。这俩个参数分别保存着参数列表变化前后的完整URL。

8.设备事件

orientationchange:设备查看模式
MozOrientation:设备平面方向改变
deviceorientation:设备空间方向变化
devicemotion:设备是否移动

9.触摸与手势事件

触摸事件

touchstarttouchmovetouchendtouchcanceltouchestargetToucheschangeTouches

手势事件

gesturestartgesturechangegestureend


五、内存和性能

每个函数都是对象,都会占用内存;内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。

1.事件委托

事件委托利用事件冒泡,指定的一个事件处理程序,就可以管理某一类型的所有事件。

<ul id="myLinks">
	<li id="goSomewhere">Go somewhere</li>
	<li id="doSomething">Do something</li>
	<li id="sayHi">Say hi</li>
</ul>

<script type="text/javascript">
var list = document.getElementById("myLinks");

EventUtil.addHandler(list,"click",function(event){
	event = EventUtil.getEvent(event);
	var target = EventUtil.getTarget(event);

	switch(target.id){
		case "doSomething":
			document.title = "change the document title";
			break;
		case "goSomewhere":
			location.href = "http://www.baidu.com";
			break;
		case "sayHi":
			alert("hi");
			break;
	}
});
</script>

2.移除事件处理程序

内存中留有那些过时不用的"空事件处理程序",也是造成Web应用程序内存和性能问题的主要原因。
所有在不需要的时候移除事件处理程序,也是解决的一种方案。

<div id="myDiv">
	<input type="button" value="Click Me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(){

	//执行某些操作
	btn.onclick = null;		//移除事件处理程序

	document.getElementById("myDiv").innerHTML = "Processing...";
};
</script>

一般来说,最好的做法就是在页面卸载之前,先通过onunload事件处理程序移除所有事件处理程序。


六、模拟事件

1.DOM中的事件模拟

可以在document对象上使用createEvent()方法创建event对象。
这个方法接收一个参数,即表示要创建的事件类型的字符串。
字符串参数可以是一下值:

  • UIEvents:一般的UI事件;
  • MouseEvents:一般化的鼠标事件;
  • MutationEvents:一般化的DOM变动事件;
  • HTMLEvents:一般化的HTML事件;

dispatchEvent()方法,所有支持事件的DOM节点都支持这个方法。调用该方法时,需要传入一个参数,即表示要触发事件的event对象。

2.IE中的事件模拟

调用document.createEventObject()方法可以在IE中创建event对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值