JavaScript与HTML之间的交互是通过事件实现的。

一、事件流

  首先我们要明白事件流的概念。当我们点击一个按钮时,也点击了按钮的容器元素,甚至也点击了整个事件。事件流描述就是从页面中接收事件的顺序。在主流浏览器中有两种事件接收方式。一种是IE提出的事件冒泡流,另一种是Netscape提出的事件捕获流。顾名思义,事件冒泡流是从被点击的最小元素逐渐向上索引DOM树,而事件捕获的思想是不太具体的节点先捕捉到事件,然后事件沿DOM树逐渐向下,一直传播到事件的实际目标。

  由于老版本浏览器不支持事件捕获模型,所以建议开发人员尽量使用事件冒泡,在有特殊需要的情况下再使用事件捕获。

二、事件处理程序

  事件就是用户或浏览器自身执行的某种动作,如click,load,mouseover,都是事件的名字;而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以on开头,onclick,onmouseover相信大家都相当熟悉了。

2.1 HTML事件处理程序

  <input type="button" value="click" onclick="alert(&quot;click!&quot;)">        //click!
<input type="button" value="click2" onclick="alert(event.type)">         //click
<input type="button" value="click3" onclick="alert(this.value)">         //click3

在指定了事件处理程序之后,会创建一个封装着元素属性的函数。这个函数中有一个局部变量event,也就是事件对象。还有一个局部变量this,等于事件的目标元素。

由于HTML事件处理程序会使HTML和JavaScript代码紧密耦合,所以许多开发人员都摈弃了HTML事件处理程序,转而使用JavaScript指定事件处理程序。

2.2 DOM0级事件处理程序

简单来说,就是在JS中,将一个函数赋值给一个元素的事件处理程序属性。这个时候,使用DOM0级方法制定的事件处理程序被认为是元素的方法。因此这时候的事件处理程序是在元素的作用域中运行,即可以在事件处理程序中通过this访问元素的任何属性和方法。

var btn = document.getElementById("btn");
btn.onclick = function(){ //此时onclick事件处理程序是元素的方法
alert(this.value);
}

在DOM0级事件处理程序是通过把函数实例的引用指派到DOM元素的属性而声明的。 

DOM第0级的缺点是,属性被用于存储作为事件处理程序的函数的引用,所以每个元素对于任何特定的事件类型,每次只能注册一个事件处理程序。 

2.3 DOM2级事件处理程序

DOM第2级事件模型(也称为监听器)被设计来解决这些类型的问题。每个DOM元素都定义名为addEventListener()的方法,用于把事件处理程序(监听器)附加到元素上。这个方法的格式如下所示: addEventListener(enentType,listener,useCapture) ;

使用DOM2级处理程序,我们能在同一个元素上为同一个事件类型建立多个事件处理程序。

2.4 IE事件处理程序

IE实现了与DOM类似的两个方法:attachEvent()和detachEvent()。需要注意的是,传入attachEvent中的参数是"onclick", 而不是DOM方法中的"click"。在IE中使用attachEvent()与DOM0级方法的主要区别在于事件处理程序的作用域。该方法会在全局作用域中运行,因此this等于window,在编写跨浏览器的代码时,这一点非常重要。attachEvent()和addEventListerner()一样,都可以多次为元素添加事件处理程序。但不同的是,attachEvent()是从后往前执行的。

2.5 兼容IE和其他浏览器的事件处理程序

var EventUtil = {
addHandler: function (element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
removeHandler: function (element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}, getEvent: function (event) {
return event ? event : window.event;
},
getTarget: function (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.cancelBubbles = true;
}
},
getRelatedTarget: function (event) {
if (event.relatedTarger) {
return event.relatedTarget;
} else if (event.toElement) {
return event.toElement;
} else if (event.fromElement) {
return event.fromElement;
} else { return null; } } }

三、事件对象

事件对象(event)包含了所有与事件相关的信息。所有的浏览器都支持事件对象(event),只不过支持的方式不同。

3.1 DOM中的事件对象

兼容DOM的浏览器会将一个event事件传入到事件处理程序中。无论指定事件处理程序用的是什么方法(DOM0还是DOM2级)。

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

/*DOM 0 级方法指定事件处理程序*/
btn.onclick = function(event){
console.log(event.type);
};
/*DOM 2 级方法指定事件处理程序*/
btn.addEventListener("click", function(event){
console.log(event.type);
}, false);

在事件处理程序内部,始终存在三个对象:this, target, currentTarget. 其中this和currentTarget包含相同的值——是事件处理程序被指定的目标元素;而target则包含的是事件的实际目标。当直接将事件处理程序指定给目标元素时,this, target 和 currentTarget 包含相同的值。

var btn = document.getElementById("myBtn");
btn.onclick = function(event){
console.log(event.target == this); //true
console.log(event.currentTarget == this); //true
}; /*如果事件处理程序存在于按钮的父节点中*/
var body =document.body;
body.onclick = function(event){
console.log(event.target == this);//target对象包含的是btn
console.log(event.currentTarget == this); //都包含body
};

stopPropagation()方法可以用于立即停止事件在DOM层次中的传播,即取消进一步的事件捕获或冒泡,从而避免出发注册在document.body上的事件处理程序,如下例子所示,当点击btn的时候,body的事件处理程序不会被触发,因为事件冒泡被及时取消了。

var btn = document.getElementById("myBtn");
var body = document.body;
btn.onclick = function(event){
console.log("btn was clicked!");
event.stopPropagation();
}; body.onclick = function(event){
console.log("body was clicked");
};

3.2 IE中的事件对象

首先需要明细的是,IE中不存在event.target,而是event.srcElement; firefox只支持target, chrome两个都支持。介于使用this不一定能获取到当前被触发的元素,所以建议编程者们使用target和srcElement获取目标元素。

此外,若在IE中使用DOM 0级制定事件处理程序,则event对象作为window对象的一个属性而存在,需要通过window.event调用;而若是使用attachEvent绑定事件,则event对象会作为参数被传入事件处理程序中。

四、事件类型

Web浏览器中可能发生的事件类型有很多,不同的事件类型具有不同的信息,而“DOM3级事件”规定了以下几类事件。

UI事件,焦点事件,鼠标事件,滚轮事件,文本事件,键盘事件,合成事件,变动事件。每种事件类型都包含了多种事件,这里不做过多阐述,最好还是在实际应用中选择重要的记忆。

这里要着重提一下HTML5事件。

1.contextmenu事件——用于自定义右键弹出的菜单。

2.beforeunload事件——用于阻止页面卸载

3.pageshow事件——在页面显示时被触发。若页面重新加载,则先出发load,再出发pageshow;若页面来自缓存,则pageshow立即被触发。

五、内存和性能

添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能。由于浏览器必须事先指定所有事件处理程序而大量访问DOM,会延迟整个页面的交互时间。

对“事件处理程序过多"问题的解决办法就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

<!--我需要为这三个列表项添加事件-->
<ul id="myLinks">
<li id="goSomewhere">go somewhere</li>
<li id="doSomething">do something</li>
<li id="sayHi">say hi</li>
</ul>
/*正常情况下我需要为这三个元素分别指派事件*/
/*注意:要将此脚本写在DOM的底部,否则脚本无法获取DOM元素会出现null*/
var item1=document.getElementById("goSomewhere");
var item2=document.getElementById("doSomething");
var item3=document.getElementById("sayHi"); item1.addEventListener("click",function(event){location.href="http://www.baidu.com";},false);
item2.addEventListener("click",function(event){document.title="look!";},false);
item3.addEventListener("click",function(event){alert("Hi!");},false);
 var list = document.getElementById("myLinks");  //使用事件委托,只需在DOM树中尽量最高的层次上添加一个事件处理程序

    list.addEventListener("click", function(event){
var target = event.target;
switch(target.id){
case "goSomewhere":
location.href = "http://www.baidu.com";
break;
case "doSomething":
document.title = "look!";
break;
case "sayHi":
alert("Hi!");
break;
}
}, false);

此外,还可以在不需要时移除事件处理程序。当带有事件处理程序的DOM被移除了(例如使用了removeChild()或innerHTML)则添加到该元素上的事件处理程序则无法被回收。因此,当你知道某个元素即将被移除的时候,那么最好手工移除该事件处理程序。并且在浏览器卸载页面之前(unonload)移除页面的所有事件处理程序。

btn.onclick=function(){
btn.onclick=null;
...
})

六、模拟事件

模拟事件的三个步骤:1、创建event对象;2、初始化事件对象;3、触发事件。

var btn =document.getElementById("btn");
var event = document.createEvent("MouseEvents"); //创建event对象
event.initEvent("click",true,true); //初始化事件对象
btn.dispatchEvent(event); //触发事件

JavaScript高级程序设计-13:事件的更多相关文章

  1. 《JAVASCRIPT高级程序设计》事件委托和模拟事件

    由于事件处理程序可以为现代web应用提供交互能力,因此许多开发人员不分青红皂白向页面中添加大量的处理程序:这在某些语言中不会导致问题,但是在javascript,事件处理程序数量直接关系到页面的整体运 ...

  2. 《JAVASCRIPT高级程序设计》事件处理程序和事件类型

    一.事件流 谈到事件,首要要理解事件流的概念:事件流是指从页面接受事件的顺序:“DOM2级事件”规定事件流包括三个阶段:事件捕获阶段.处于目标阶段和事件冒泡阶段.目前大部分的浏览器的事件流是事件冒泡, ...

  3. JavaScript高级程序设计笔记 事件冒泡和事件捕获

    1.事件冒泡 要理解事件冒泡,就得先知道事件流.事件流描述的是从页面接收事件的顺序,比如如下的代码: <body> <div> click me! </div> & ...

  4. javascript高级程序设计---拖拉事件

    拖拉事件 拖拉指的是,用户在某个对象上按下鼠标键不放,拖动它到另一个位置,然后释放鼠标键,将该对象放在那里. 拖拉的对象有好几种,包括Element节点.图片.链接.选中的文字等等.在HTML网页中, ...

  5. javascript高级程序设计---js事件思维导图

    绘制思维软件与平时用的笔记,以及导出功能,这三个问题综合起来,于是我把思维导图分开画 1.js事件的基本概念 2.js事件的事件处理程序 3.js事件的事件对象

  6. JavaScript高级程序设计13.pdf

    使用hasOwnProperty()方法检测一个属性存在实例还是原形中,当属性存在对象实例中时,返回true alert(person1.hasOwnProperty("name" ...

  7. 《javascript高级程序设计》 touch事件的一个小错误

    最近一段时候都在拜读尼古拉斯大神的<javascript高级程序设计>,真的是一本好书,通俗易懂,条理比<javascript权威指南>好理解一些,当然<javascri ...

  8. 读书笔记(05) - 事件 - JavaScript高级程序设计

    HTML依托于JavaScript来实现用户与WEB网页之间的动态交互,接收用户操作并做出相应的反馈,而事件在此间则充当桥梁的重要角色. 日常开发中,经常会为某个元素绑定一个事件,编写相应的业务逻辑, ...

  9. 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介

    前言: 为什么会想到把<JavaScript 高级程序设计(第 3 版)>总结记录呢,之前写过一篇博客,研究的轮播效果,后来又去看了<JavaScript 高级程序设计(第3版)&g ...

随机推荐

  1. Oracle Sql优化之lead,lag分析函数

    1.表中有四个字段:人员编号,开始时间,结束时间,类型,数据ID,需要实现如下需求 a.当类型为-1时,丢弃该记录 b.当类型为-1时,且前一行结束时间为null,当前行的开始时间-1作为前一行的结束 ...

  2. HDU 5739 Fantasia

    可以将这个图转换成森林来进行树形dp求解.看了这篇具体教学才会的:http://www.cnblogs.com/WABoss/p/5696926.html 大致思路:求解一下点双连通分量(Tarjan ...

  3. L7,too late

    words: parcel,包裹 detective,侦探 expect,期待 airfield,飞机起落的场地 guard,警戒,守卫,n precious,adj,珍贵的 stone,石头 exp ...

  4. shell输出不换行符合换行符

    输出不换行符 例如 echo "Hello\c" echo " World" //Hello World 输出换行符 echo "username\n ...

  5. 为什么MVC不是一种设计模式? ---比较Backbone和Ext4.x在MVC实现上的差异

    为什么MVC不是一种设计模式? ---比较Backbone和Ext4.x在MVC实现上的差异 大漠穷秋 前言 圣人云:不想做妈咪的小姐不是好码农. 每一个码农的心中都有一个终极理想,那就是有一天不用再 ...

  6. java删除文件夹 Java中实现复制文件或文件夹

    删除文件夹 import java.io.File; public class DeleteDir { /** * @param args */ public static void main(Str ...

  7. 1084:XX开公司<回溯>

    Description 2020年,xx开了一家拥有N个员工的大公司.每天,xx都要分配N项工作给他的员工,但是,由于能力的不同,每个人对处理相同工作所需要的时间有快有慢.众所周知,xx是一个非常重视 ...

  8. android — JNI注册方法说明

    Jni中还可以采用RegisterNatives来注册jni的方法,注册以后的jni函数的命名可以不需要符合类似javah命令生成的函数的规则 RegisterNatives为JNIEnv的成员函数, ...

  9. CodeForces 609B The Best Gift

    统计+枚举 #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> ...

  10. 利用rem实现webapp布局

    rem这是个低调的css单位,近一两年开始崭露头角,有许多同学对rem的评价不一,有的在尝试使用,有的在使用过程中遇到坑就弃用了. 但是我对rem综合评价是用来做web app它绝对是最合适的人选之一 ...