JavaScript高级程序设计-13:事件
JavaScript与HTML之间的交互是通过事件实现的。
一、事件流
首先我们要明白事件流的概念。当我们点击一个按钮时,也点击了按钮的容器元素,甚至也点击了整个事件。事件流描述就是从页面中接收事件的顺序。在主流浏览器中有两种事件接收方式。一种是IE提出的事件冒泡流,另一种是Netscape提出的事件捕获流。顾名思义,事件冒泡流是从被点击的最小元素逐渐向上索引DOM树,而事件捕获的思想是不太具体的节点先捕捉到事件,然后事件沿DOM树逐渐向下,一直传播到事件的实际目标。
由于老版本浏览器不支持事件捕获模型,所以建议开发人员尽量使用事件冒泡,在有特殊需要的情况下再使用事件捕获。
二、事件处理程序
事件就是用户或浏览器自身执行的某种动作,如click,load,mouseover,都是事件的名字;而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以on开头,onclick,onmouseover相信大家都相当熟悉了。
2.1 HTML事件处理程序
<input type="button" value="click" onclick="alert("click!")"> //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:事件的更多相关文章
- 《JAVASCRIPT高级程序设计》事件委托和模拟事件
由于事件处理程序可以为现代web应用提供交互能力,因此许多开发人员不分青红皂白向页面中添加大量的处理程序:这在某些语言中不会导致问题,但是在javascript,事件处理程序数量直接关系到页面的整体运 ...
- 《JAVASCRIPT高级程序设计》事件处理程序和事件类型
一.事件流 谈到事件,首要要理解事件流的概念:事件流是指从页面接受事件的顺序:“DOM2级事件”规定事件流包括三个阶段:事件捕获阶段.处于目标阶段和事件冒泡阶段.目前大部分的浏览器的事件流是事件冒泡, ...
- JavaScript高级程序设计笔记 事件冒泡和事件捕获
1.事件冒泡 要理解事件冒泡,就得先知道事件流.事件流描述的是从页面接收事件的顺序,比如如下的代码: <body> <div> click me! </div> & ...
- javascript高级程序设计---拖拉事件
拖拉事件 拖拉指的是,用户在某个对象上按下鼠标键不放,拖动它到另一个位置,然后释放鼠标键,将该对象放在那里. 拖拉的对象有好几种,包括Element节点.图片.链接.选中的文字等等.在HTML网页中, ...
- javascript高级程序设计---js事件思维导图
绘制思维软件与平时用的笔记,以及导出功能,这三个问题综合起来,于是我把思维导图分开画 1.js事件的基本概念 2.js事件的事件处理程序 3.js事件的事件对象
- JavaScript高级程序设计13.pdf
使用hasOwnProperty()方法检测一个属性存在实例还是原形中,当属性存在对象实例中时,返回true alert(person1.hasOwnProperty("name" ...
- 《javascript高级程序设计》 touch事件的一个小错误
最近一段时候都在拜读尼古拉斯大神的<javascript高级程序设计>,真的是一本好书,通俗易懂,条理比<javascript权威指南>好理解一些,当然<javascri ...
- 读书笔记(05) - 事件 - JavaScript高级程序设计
HTML依托于JavaScript来实现用户与WEB网页之间的动态交互,接收用户操作并做出相应的反馈,而事件在此间则充当桥梁的重要角色. 日常开发中,经常会为某个元素绑定一个事件,编写相应的业务逻辑, ...
- 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介
前言: 为什么会想到把<JavaScript 高级程序设计(第 3 版)>总结记录呢,之前写过一篇博客,研究的轮播效果,后来又去看了<JavaScript 高级程序设计(第3版)&g ...
随机推荐
- Linux中的挂载和卸载
mkdir /home/xxx 创建挂载点 mount /dev/cdrom /home/xxx 把cdrom中的内容挂载到xxx目录 umount /dev/cdrom 卸载 /dev/sr ...
- play1.x vs play2.x 对比(转)
个人看到对比play1.x和play2.x比较的文章中,写的最深入,最清晰的一个.转自:http://freewind.me/blog/20120728/965.html 为了方便群中的Play初学者 ...
- 使用ReTrofit做缓存(结合上拉加载和下拉刷新)
1. noCache 不使用缓存,全部走网络 2. noStore 不使用缓存,也不存储缓存 3. onlyIfCached 只使用缓存 4. maxAge 设置最大失效时间,失效则不使用 需要服务器 ...
- angularjs三级联动
<div ng-controller="AjaxCtrl"> <h1>AJAX - Oriented</h1> <div> Coun ...
- 使用print2flash开发在线文档
www.print2flash.com 命令行调用: A:\Program Files (x86)\Print2Flash3>p2fServer.exe a.pdf a.swf
- Developing Backbone.js Applications
https://addyosmani.com/backbone-fundamentals/
- Python3基础 list() 将一个元组转换成列表
镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...
- 进程间通信——FIFO(多个客户进程,一个服务进程)
FIFO简介 FIFO就是Unix的一种复合POSIX标准的进程间通信机制.他又称为命名管道,跟管道的不同点是,每个FIFO都有一个路径名与之关联. FIFO虽然有路径名,但是他这中文件是在内核态(管 ...
- openssl windows编译 32位&64位
openssl版本:openssl-1.0.0k 64位编译 1.编译环境: openssl-1.0.0a必须用vs2008编译(Open Visual Studio 2008 x64 Cross T ...
- centos lvm常用命令
# vgs -a VG #PV #LV #SN Attr VSize VFree cinder 1 0 0 wz--n- 30.39g 30.39g os ...