JavaScript高级程序设计:第十三章

第十三章

一、理解事件流

事件流描述的是从页面中接收事件的顺序。

1.事件冒泡

IE的事件流叫做事件冒泡,即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点。以下面的HTML页面为例:

<!DOCTYPE html>

<html>

<head>

<title>Event Bubling Example</title>

</head>

<body>

<div id="myDiv">Click Me</div>

</body>

</html>

如果你单机了页面中的<div>元素,那么这个click事件会按照如下顺序传播:

①<div>

②<body>

③<html>

④document

也就是说,click事件首先在<div>元素上发生,而这个元素就是我们单击的元素。然后click事件沿DOM树向上传播,在每一级节点上都会发生,直至传播到document对象。

2.事件捕获

另一种事件流叫做事件捕获。事件捕获的思想是不太具体的节点应该更早的接收到事件。如果仍以前面的页面作为演示事件捕获的例子,那么单击<div>元素就会以下列顺序触发click事件。

①document

②<html>

③<body>

④<div>

在事件捕获过程中,document对象首先接收到click事件,然后事件沿DOM树依次向下,一直传播到事件的实际目标,即<div>元素。

3.DOM事件流

“DOM2级事件”规定的事件流包括三个阶段:事件的捕获阶段、处于目标阶段和事件冒泡阶段。

二、事件处理程序

1.HTML事件处理程序

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

在HTML中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的脚本,如下面的例子所示:

<script  type = “text/javascript”>

function  showMessage(){

alert(“Hello world!”);

}

</script>

<input  type = “button”  value = “Click  Me”  onclick = “showMessage()”  />

在这个例子中,单击按钮就会调用showMessage()函数。这个函数是在一个独立的<script>元素中定义的,当然代码也可以被包含在一个外部文件中,事件处理程序中的代码在执行时,有权访问全局作用域中的任何代码。

这样指定事件处理程序有一些独到之处。首先会创建一个封装着元素属性值的函数。这个函数中有一个局部变量event,也就是事件对象:

<!—输出“click”-->

<input type=”button” value=”click Me” onclick =”alert(event.type)”>

通过event变量,可以直接访问事件对象,你不用自己定义它,也不用从函数的参数列表中读取。在这个函数内部,this值等于事件的目标元素,例如:

<!—输出”Click Me”-->

<input type=”button” value=”Click Me” onclick=”alert(this.value)”>

关于这个动态创建函数,另一个有意思的地方是它扩展作用域的方式。在这个函数内部,可以像访问局部变量一样访问document及该元素本身的成员。

2.DOM0级事件处理程序

通过javascript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。

每个元素,都有自己的事件处理程序属性,这些属性通常全部小写,例如onclick。将这种属性的值设置为一个函数,就可以指定事件处理程序,如下所示:

var btn = document.getElementById(“myBtn”) ;

btn.onclick = function() {

alert(“Clicked”) ;

} ;

在此,我们通过文档对象取得了一个按钮的引用,然后为它指定了onclick事件处理程序。使用DOM0级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序中的this引用当前元素。来看一个例子:

var btn = document.getElementById(“myBtn”) ;

btn.onclick = function() {

alert(this.id) ;         //”myBtn”

} ;

单击按钮显示的是元素的ID,这个ID是通过this.id取得的。

也可以通过删除DOM0级方法指定的事件处理程序,只要像下面这样将事件处理程序属性的值设置为null即可:

btn.onclick = null ; //删除事件处理程序

3.DOM2级事件处理程序

“DOM2级事件”定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener() 和 removeEventListener()。所有DOM节点中都包含这两个方法,并且它们都接受3个参数:要处理的事件名、作为事件处理程序和函数的一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。

使用DMO2级方法添加事件处理程序的主要好处是可以添加多个事件处理程序。来看下面的例子。

var btn = document.getElementById("myBtn");

btn.addEventListener("click",function(){

alert(this.id);

},false);

btn.addEventListener("click",function(){

alert("Hello world!");

},false);

通过addEventListener() 添加的事件处理程序只能用removeEventListener()来移除;移除同时传入的参数与添加处理程序时使用的参数相同。这意味着通过addEventListener() 添加的匿名函数将无法移除。

4.IE事件处理程序

IE实现了与DOM中类似的两个方法:attachEvent()和detachEvent()。这两个方法接收相同的2个参数:事件处理程序名称好事件处理程序函数。与DOM方法不同的是:

(1)DOM0级方法事件处理程序会在其所属元素的作用域中运行,而attachEvent()方法在全局作用域中运行。

(2)attachEvent()事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。

5.跨浏览器的事件处理程序

第一个要创建的方法是addHandler(),它的职责是视情况分别使用DOM0级方法、DOM2级方法或IE方法来添加事件。这个方法属于一个名叫EventUtil的对象,它接受3个参数:要操作的元素、事件名称和事件处理程序函数。

与addHandler()对应的方法是removeHandler(),它也接受相同的参数。这个方法的职责是移除之前添加的事件处理程序——无论该事件处理程序是采取什么方式添加到元素中的,如果其他方法无效,默认采用DOM0级方法。

三、事件对象

1.DOM中的事件对象

兼容DOM的浏览器会将一个event对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法,都会传入event对象。来看下面的例子:

var btn = document.getElementById(“myBtn”) ;

btn.onclick = function(event){

           alert(”event.type”);

};

btn.addEventListener(“click” ,function(event){

alert(event.type);      //“click”

},false);

这个例子中的两个事件处理程序都会弹出一个警告框,显示由event.type属性表示的事件类型。

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”

};

通过window.event取得了event对象,并检测了被触发事件的类型。

3.跨浏览器的事件对象

虽然DOM和IE中的event对象不同,但基于它们之间的相似性依旧可以拿出跨浏览器的方案来。IE中event对象的全部信息和方法DOM对象中都有,只不过实现方式不一样。不过,这种对应关系让实现两种事件模型之间的映射非常容易。

4.事件类型

(1)UI事件,当用户与页面上的元素交互时触发;

(2)焦点事件,当元素获得或是去焦点时触发;

(3)鼠标事件,当用户通过鼠标在页面上执行操作时触发;

(4)滚轮事件,当使用鼠标滚轮时触发;

(5)文本事件,当在文档中输入文本时触发;

(6)键盘事件,当用户通过键盘在页面上执行操作时触发;

(7)合成事件,当为IEM输入字符时触发;

(8)变动事件,当底层DOM结构发生变化时触发。

(9)变动名称事件,当元素或属性名变动时触发。此类事件已经被废弃,没有任何浏览器实现它们。

五、性能和内存

1.事件委托

对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。例如,click事件会一直冒泡到document层次。也就是说,我们可以为整个页面指定一个onclick事件处理程序,而不必给每个可单击的元素分别添加事件处理程序。以下面的HTML代码为例:

<ul id=”myLinks”>

<li id=”goSomewhere”>Go somewhere</li>

<li id=”doSomething”>Do something</li>

<li id=”sayHi”>Say hi</li>

</ul>

其中包含3个被单击后会执行操作的列表项。按照传统做法,需要像下面这样为它们添加3个事件处理程序。

var item1=document.getElementById("goSomewhere");

var item2=document.getElementById("doSomething");

var item3=document.getElementById("sayHi");

EventUtil.addHandler(item1,"click",function(event){

location.href="http://www.wrox.com";

});

EventUtil.addHandler(item2,"click",function(event){

document.title="I changed the document‘s title";

});

EventUtil.addHandler(item3,"click",function(event){

alert("hi");

});

如果在一个复杂的web应用程序中,对所有可单击的元素都采用这种方式,那么结果就会有数不清的代码用于添加事件处理程序。此时,可以利用事件委托技术解决这个问题。使用事件委托,只需在DOM树中尽量最高的层次上添加一个事件处理程序,如下面的例子。

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="I changed the document‘s title";

break;

case "goSomewhere";

location.href="http://www.wrox.com";

break;

case "sayHi";

alert("hi");

break;

}

});

2.移除事件处理程序

每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的javascript代码之间就会建立一个连接。这种连接越多,页面执行起来就越慢。如前所述,可以采用事件委托技术,限制建立的链接数量。另外,在不需要的时候移除事件处理程序,也是解决这个问题的一种方案。内存中留有那些过时不用的“空事件处理程序”,也是造成Web应用程序内存与性能问题的主要原因。

在两种情况下,可能会造成上述问题:第一种情况就是从文档中移除带有事件处理程序的元素时。第二种情况就是卸载页面的时候。

六、模拟事件

1.DOM中的事件模拟

可以在document对象上使用createEvent()方法创建event对象。这个方法接收一个参数,即表示要创建的事件类型的字符串。在DOM2级中所有这些字符串都是使用英文复数形式,而在DOM3级中变成了单数。

(1)模拟鼠标事件

创建新的鼠标事件对象并为其指定必要的信息就可以模拟鼠标事件。创建鼠标事件对象的方法是为createEvent()传入字符串“MouseEvents”。返回的对象有一个名为initMouseEvent()方法,用于指定与该鼠标事件有关的信息。这个方法接收15个参数。下面, 我们通过一个例子了解如何模拟对按钮的单击事件:

var btn=document.getElementById(“myBtn”);

// 创建事件对象

var event = document.createEvent(“MouseEvents”);

//初始化事件对象

event.initMouseEvent(“click”,true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);

//触发事件

btn.dispatchEvent(event);

(2)模拟键盘事件

DOM3级规定,调用createEvent()并传入“keyboardEvent”就可以创建一个键盘事件。返回的事件对象会包含一个initKeyEvent()方法。

由于DOM3级不倡导使用keypress事件,因此只能利用这种技术来模拟keydown和keyup事件。

var textbox=document.getElementyById(“myTextbox”),event;

//以DOM3级方式创建事件对象

if (document.implementation.hasFeature(“KeyboardEvents”,”3.0”)){

event=document.createEvent(“KeyboardEvent”);

//初始化事件对象

event.initKeyboardEvent(“keydown”,true,true,document.defaultView,”a”,0,”shift”,0);

}

//触发事件

textbox.dispatchEvent(event);

这个例子模拟的是按住shift键的同时又按下A键。

在其他浏览器中,则需要创建一个通用的事件,然后再向事件对象中添加键盘事件特有的信息。例如:

var textbox=document.getElementById(“myTextbox”);

//创建事件对象

var event=document.createEvent(“Events”);

//初始化事件对象

event.initEven(type,bubbles,cancelable);

event.view=document.defaultView’

event.altKey=false;

event.ctrlKey=false;

event.shiftKey=false;

event.metaKey=false;

event.keyCode=65;

event.charCode=65;

//触发事件

textbox.dispatchEvent(event);

3.模拟其他事件

虽然鼠标事件和键盘事件是在浏览器中最经常模拟的事件,但有时候同样需要模拟变动事件和HTML事件。要模拟变动事件,可以使用createEvent(“MutationEvents”)创建一个包含initMutationEvent()方法的变动事件对象。例如:

var event=document.createEven(“MutationEvents”) ;

event.initMutationEvent(“DOMNodeInserted”,true,false,someNode,””,””,””,0);

target.dispatchEvent(event);

以上代码模拟了DOMNodeInserted事件。其他变动事件可以按照这个样子来模拟,只要改一改参数。

4.自定义DOM事件

自定义事件不是由DOM原生触发的,它的目的是让开发人员创建自己的事件。要创建新的定义事件,可以调用createEvent(“CustomEvent”)。返回的对象有一个名为initCustomEvent()的方法。

2.IE中的事件模拟

调用document.createEventObject()方法可以在IE中创建event对象。这个方法不接受参数,结果会返回一个通用的event对象。然后,手工为这个对象添加所有必要的信息。最后一步就是在目标上调用fireEvent()方法,这个方法接受两个参数:事件处理程序的名称和event对象。在调用fireEvent()方法时,会自动为event对象添加srcElement和type属性;其他属性则都必须通过手工添加。

时间: 2024-10-23 11:32:29

JavaScript高级程序设计:第十三章的相关文章

javascript高级程序设计 第十三章--事件

javascript高级程序设计 第十三章--事件js与HTML的交互就是通过事件实现的,事件就是文档或浏览器窗口中发生的一些特定的交互瞬间. 事件流:事件流描述的是从页面中接收事件的顺序,IE的是事件冒泡流,Netscape的是事件捕获流,这个两个是完全相反的事件流概念. 事件冒泡:由最具体的元素接收,然后逐级向上传播到更高级的节点,即事件沿DOM树向上传播,直到document对象. 事件捕获:不大具体的节点应该更早接收到事件,相当于沿DOM节点树向下级传播直到事件的实际目标,在浏览器中,是

javascript高级程序设计 第十一章--DOM扩展

javascript高级程序设计 第十一章--DOM扩展DOM最主要的扩展就是选择符API.HTML5和Element Traversal Selectors API:定义了两个方法 querySelector() 和 querySelectorAll(),能够基于CSS选择符从DOM中取得元素.querySelector()方法接收一个CSS选择符,返回该模式匹配的第一个元素,querySelectorAll()接收的参数一样,但是返回NodeList实例: matchesSelector()

Javascript高级程序设计——第三章:基本概念

javascript高级程序设计——第三章:基本概念 一.语法 EMCA-262通过叫做ECMAScript的“伪语言”为我们描述了javascript实现的基本概念 javascript借鉴了C的语法,区分大小写,标示符以字母.下划线.或美元符号($)开头,注释可以用 // 或者/* */ 严格模式: ECMAScript 5引入了严格模式,在严格模式下不确定的行为将得到处理,通过在顶部添加 “use strict”来启用严格模式: function fuc(){ "use strict&qu

《JavaScript高级程序设计第五章--引用类型》之Object对象和array对象

这一章主要就是介绍各种内置对象的用法,认识其经常用到的属性和方法. 5.1Object类型 创建objec的方式,一种是new Object(),一种是对象字面量(简化创建包含大量属性的对象的过程) var person = { name = "Nicholas"; age = 27 };//最后一个属性不必添加逗号,ie7等会导致错误 //在使用对象字面量语法时,属性名也可以使用字符串.这里的数值属性会自动转字符串. var person = { "name" :

javascript高级程序设计 1 ~ 3 章 部分知识点总结

第一章 javascript简介 javascript的简介,有关js的一些历史问题. js初期在不同的浏览器存在很大的兼容问题,但是慢慢的大家都在向标准靠拢,兼容问题已经好很多了. 我们通常会听到ECMAScript,它跟javascript是什么关系呢? JS = ES + BOM(浏览器对象模型) + DOM(文档对象模型)  ES就是对javascript的类型,值,对象,属性,函数以及程序句法和语义,DOM就是ES运行在浏览器环境的时候,浏览器为其提供的扩展以实现更多更具体的功能(we

《JAVASCRIPT高级程序设计》第一章

在使用调制解调器的时代,频繁的表单验证对客户端来说是一个很大的负担,javascript,作为一种专门进行表单验证的客户端脚本语言诞生了.到今天,javascript早已超越了当初设定的角色.Javascript由以下三部分组成: 核心(ECMAScript) 文档对象模型(DOM) 浏览器对象模式(BOM) 一.ECMAScript ECMAScript是对Javascript这门语言的描述,它规定了这门语言的这些组成部分:语法.类型.语句.关键字.保留字.操作符.对象.Web浏览器是ECMA

JavaScript高级程序设计第20章JSON 笔记 (学习笔记)

第二十章 JSON 1.Json 可以表示三种类型的值: 1.简单值: 表示数值:5  表示字符串:“hello wrold”注表示字符串时必须使用双引号 2.对象: {“name”:“mi”,”age”:24}与JavaScript对象有两处不同一是没有声明变量 二是没有末尾的分号json对象中属性必须带引号,对象里的值可以嵌套对象. 3.数组 Json数组表示:[25,”hi”,true]和json对象一样json里也没有分号和变量 2.json对象 1.Stringify()方法用于把ja

JavaScript高级程序设计第14章表单脚本 (学习笔记)

第十四章 表单脚本 1.阻止默认表单提交 1.提交表单数据 1.使用type=submit提交按钮 2.使用submit():方法 注意:当用户点击提交按钮时,会触发submit事件,从而在这里我们有机会验证数据并决定要不要提交表单 1.preventnDefault(event):可以用在表单数据无效时不发给服务器,对于动态绑定的onclick 事件. 2.Submit()方法也可以提交表单,但是不会触发submit事件,所以在使用时须先验证表单数据, 如:<%response.write(t

《JAVASCRIPT高级程序设计》第二章

把javascript应用在网页中,需要涉及web的核心语言-html:如何让javascript既能与html共存,又不影响页面的显示效果,经过长时间的讨论.试错,最终的决定是为web增加统一的脚本支持.向html插入javascript最主要的做法,是借助<script>标签. 如果不指定type,type默认是“text/javascript" 1)在页面嵌入JS代码 1 <script type="text/javascript"> 2 fun

JavaScript高级程序设计:第二章

在HTML中使用JavaScript 1.<script>元素:向HTML页面中插入JavaScript的主要方法就是使用<scritp>元素.HTML4.01为<script>定义了下列6个属性. (1)async:可选.表示立即下载脚本,但不妨碍页面中的其他操作,比如下载其他资源或等待加载其他脚本.只对外部脚本文件有效. (2)charset:可选.表示通过src属性指定的代码的字符集.由于大多数浏览器会忽略它的值,因此这个属性很少有人用. (3)defer:可选.