一、事件流

事件流指从页面中接收事件的顺序。

1.事件冒泡(常用)

IE中采用的事件流是事件冒泡,先从具体的接收元素,然后逐步向上传播到不具体的元素。

2.事件捕获(少用)

Netscapte采用事件捕获,先由不具体的元素接收事件,最具体的节点最后才接收到事件。

3.DOM事件流

DOM2级事件包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。

二、事件处理程序

事件处理程序就是响应某些事件的函数,如onclick等。

1. DOM0级事件处理程序

每个元素都有自己的事件处理程序属性,如onclick等。可以通过js将一个函数赋值给元素的事件处理程序属性。

在DOM0事件处理程序中,事件处理程序里的this指向当前元素。

var objlogo=document.getElementById("site_nav_top");
objlogo.onclick=function(){
alert(this.innerHTML);//代码改变世界
}

删除DOM0事件,只需将事件处理程序的值赋为null即可。

objlogo.onclick=null;

2. DOM2级事件处理程序

DOM2有两个方法用来添加和移除事件处理程序:addEventListener()和removeEventListener()。它们都有三个参数:第一个参数是事件名(如click);第二个参数是事件处理程序函数;第三个参数如果是true则表示在捕获阶段调用,为false表示在冒泡阶段调用。

  • addEventListener():可以为元素添加多个事件处理程序,触发时会按照添加顺序依次调用。
  • removeEventListener():不能移除匿名添加的函数。
//不能移除
var obj = document.getElementById('site_nav_top');
obj.addEventListener('click', function () {
  alert(this.innerHTML);
}, false);
obj.removeEventListener('click', function () {
  alert(this.innerHTML);
}, false);
//能移除
var obj=document.getElementById("site_nav_top");
var show=function(){
alert(this.innerHTML);
}
obj.addEventListener("click",show,false);
obj.removeEventListener("click",show,false);

3.IE事件处理程序

IE的事件处理程序也有两个类似的方法:attachEvent()和detachEvent()。它们有两个参数:第一个是事件名(如onlick);第二个参数是事件处理程序的函数。

注意:

  • 事件名前面有on前缀;
  • 在事件处理程序的函数中,this不再指向当前元素,而是指向window对象。
var obj=document.getElementById("site_nav_top");
var show=function(){
alert(obj.innerHTML);
}
obj.attachEvent("onclick",show);
obj.detachEvent("onclick",show);

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

综合前面几种情况,进行浏览器能力检测,就可以写出跨浏览器的事件处理程序了.

EventUtil = {
addHandler: function (obj, event, handler) {
if (obj.addEventListener) {
obj.addEventListener(event, handler, false);
} else if (obj.attachEvent) {
obj.attachEvent('on' + event, handler);
} else {
obj['on' + event] = handler;
}
},
removeHandler: function (obj, event, handler) {
if (obj.removeEventListener) {
obj.removeEventListener(event, handler, false);
} else if (obj.detachEvent) {
obj.detachEvent('on' + event, handler);
} else {
obj['on' + event] = null;
}
}
};
var obj = document.getElementById('site_nav_top');
var show = function () {
alert(obj.innerHTML);
} EventUtil.addHandler(obj, 'click', show);
EventUtil.removeHandler(obj, 'click', show);

三、事件对象

当触发DOM事件时,会产生一个事件对象event。不同浏览器对该对象的支持略有不同。

1.DOM中的事件对象

在支持DOM0或DOM2的浏览器中,会将event对象传入到事件处理程序中。

var obj=document.getElementById("site_nav_top");
var show=function(event){
alert(event.type);
}
obj.addEventListener("click",show,false);//点击运行结果 click

event对象包含于创建它的事件对象相关的属性和方法。几种常用属性和方法:

① this, currentTarget 与 target:

event.this与event.currentTarget始终相等,表示事件处理程序当前正在处理的元素;

event.target表示事件的实际目标元素。

var obj=document.getElementById("site_nav_top");
var show=function(event){
console.log(this);
console.log(event.currentTarget);
console.log(event.target);
}
obj.addEventListener("click",show,false);
//点击头部“代码改变世界”结果 <div id="site_nav_top">,<div id="site_nav_top">,<div id="site_nav_top"> var show=function(event){
console.log(this);
console.log(event.currentTarget);
console.log(event.target);
}
document.body.addEventListener("click",show,false);
//点击头部“代码改变世界”结果: <body>, <body>, <div id="site_nav_top">

②event.type:被触发的事件类型,如click。通过判断该属性,可以用一个函数中处理多个事件。

var obj=document.getElementById("nav_menu");
var handler=function(event){
switch(event.type){
case "mouseover":
event.target.style.backgroundColor="red";
break;
case "mouseout":
event.target.style.backgroundColor="";
break;
case "click":
alert("click menu");
break;
}
}
obj.addEventListener("click",handler,false);
obj.addEventListener("mouseover",handler,false);
obj.addEventListener("mouseout",handler,false);

③event.preventDefault():阻止事件的默认行为。

例如在上面的例子中,单击站点导航条在弹出“click menu”后,仍然打开了链接。如果想阻止其默认行为,可以这样处理:

case "click":
alert('click menu')
event.preventDefault();
break;

④event.stopPropagation():阻止事件进一步冒泡或捕获。

var obj = document.getElementById('nav_menu');
var handler = function (event) {
alert('handler');
}
var handler1 = function (event) {
alert('handler1');
}
obj.addEventListener('click', handler, false);
document.body.addEventListener('click', handler1, false);

在这个例子中给菜单和body分别添加了单击事件,当点击菜单时会出现两次弹窗。如果想阻止事件冒泡,可以做如下修改:

var handler=function(event){
alert('handler');
event.stopPropagation();
}

2. IE中的事件对象

①event对象

使用DOM0添加的事件处理程序,event作为window对象的属性存在。

var obj=document.getElementById("nav_menu"); 

obj.onclick=function(event){
alert(window.event.type);
}

使用attachEvent添加的事件处理程序,可以将event作为函数的参数传入,也可以直接使用window.event。

var obj=document.getElementById("nav_menu");
obj.attachEvent("onclick",function(event){
alert(event.type);
alert(window.event.type);
});

②event.srcElement:事件的目标元素,等同于DOM中的target属性。

③event.returnValue:将该属性设置为false可以阻止默认事件。相当于DOM中的preventDefault()。

④event.cancelBubble:将该属性设为true可以阻止事件冒泡。相当于DOM中的 stopPropagation()。

3.跨浏览器的事件对象

综合考虑DOM和IE中的事件对象,写出跨浏览器的事件对象,放在之前的EventUtil中。

EventUtil = {
addHandler: function (obj, event, handler) {
......
},
removeHandler: function (obj, event, handler) {
......
},
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.stopPropation) {
event.stopPropation();
} else {
event.cancelBubble = true;
}
}
};
//以园子首页菜单栏为例调用
var obj = document.getElementById('nav_menu');
EventUtil.addHandler(obj, 'click', function (event) {
var event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
alert(target);
EventUtil.preventDefault(event);
EventUtil.stopPropagation(event);
});
EventUtil.addHandler(document.body, 'click', function () {
alert('body');
})

四、事件类型

1.load事件

load可以用来判断图片加载完毕。注意:新创建的图像元素不是在加载到页面中才开始下载,而是设置src之后就开始下载。

var obj = document.getElementById('site_nav_top');
EventUtil.addHandler(obj, 'click', function () {
var img = new Image();
EventUtil.addHandler(img, 'load', function () {
alert('load');
});
img.src = 'http://static.cnblogs.com/images/logo_small.gif';
obj.appendChild(img);
})

load可以用来判断js加载完成。<script>元素可以触发load事件,来判断动态加载的js文件是否加载完成。它和img不同,必须设置了src属性并且添加到文档之后才会开始下载。

EventUtil.addHandler(document.body,"click",function(){
var script=document.createElement("script");
EventUtil.addHandler(script,"load",function(){
alert('load');
});
script.src="http://common.cnblogs.com/script/jquery.js";
document.body.appendChild(script);
})

2.resize事件:当浏览器的宽度或高度变化时触发该事件。有些浏览器窗口变化1像素时就触发该事件,有的浏览器在停止调整窗口大小时才出发该事件。因此不要在该方法中写大量的计算代码,以免减缓浏览器速度。

3.获取鼠标位置

  • clientX和clientY:客户区坐标位置。表示鼠标在视口中的水平位置和垂直位置。
  • pageX和pageY:页面坐标位置。表示鼠标在页面中的位置,从页面本身而不是视口的左边和顶部开始计算的。
  • screenX和screenY:屏幕坐标位置。鼠标指针相对于整个屏幕的坐标位置。
var obj = document.getElementById('headline_block');
EventUtil.addHandler(obj, 'click', function (event) {
var result = event.clientX + ',' + event.clientY + '\r\n';
result += event.pageX + ',' + event.pageY+'\r\n';
result+=event.screenX+','+event.screenY;
alert(result);
})

4.beforeunload事件

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

要在卸载页面时显示弹窗提示,需要将event.returnValue设置为提示语,并且将该提示语作为函数的返回值。

EventUtil.addHandler(window,'beforeunload',function(event){
event=EventUtil.getEvent(event);
var msg='确认关闭吗';
event.returnValue=msg;
return msg;
});

五、内存和性能

1.事件委托

事件委托可以解决页面中事件处理程序过多的问题。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以处理某一类型的所有事件。

EventUtil.addHandler(document.body, 'click', function (event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
switch (target.id) {
case 'site_nav_top':
alert('口号');
break;
case 'nav_menu':
alert('点击菜单');
EventUtil.preventDefault(event);
break;
case 'editor_pick_lnk':
alert('推荐区');
EventUtil.preventDefault(event);
break;
}
});

2.移除事件处理程序

如果内存中保留大量无用的事件处理程序,会影响性能。所以一定要在不需要的时候及时移除事件处理程序。尤其注意以下情况:

使用innerHTML删除带有事件处理程序的元素时,要先将事件处理程序设置为null。使用委托也可以解决这个问题,不直接将事件加载会被innerHTML替换的元素,而是将事件赋给其父元素,这样就可以避免了。

卸载页面时,最好手工清除所有的事件处理程序。

六、DOM中的事件模拟

1. DOM中的事件模拟分三步:

  • 使用document.createEvent()创建event对象。通过赋值不同的参数,可以模拟不同的事件类型
  • 初始化event对象;
  • 触发事件,调用dispatchEvent()方法,所有支持事件的DOM节点都可以支持这个方法。

2. 模拟鼠标事件

首先createEvent()方法传入参数是“MouseEvent”来模拟鼠标事件。

返回的event对象有一个initMouseEvent()方法,用来初始化事件信息。该方法有15个参数:

  • type(字符串):要触发的事件类型,比如“click”。
  • bubbles(bool):事件是否冒泡。一般设为true。
  • cancelable(bool):事件是否可以取消。一般设为true。
  • view:与事件关联的视图,一般设置为document.defaultView。
  • detail(整数):与事件有关的详细信息,一般设置为0.
  • screenX:事件相对于屏幕的X坐标。
  • screenY:事件相对于屏幕的Y坐标。
  • clientX:事件相对于视口的X坐标。
  • clientY:事件相对于视口的Y坐标。
  • ctrlKey(bool):是否俺下了Ctrl键,默认为false。
  • altKey:是否按下了alt键,默认false。
  • shiftKey:是否按下了shift键,默认false。
  • metaKey:是否按下了meta键,默认false.
  • button(整数):按下了哪个鼠标键,默认0。
  • relatedTarget:与事件相关的对象,一般为null.只在模拟mouseover和mouseout的时候会用到。

最后给DOM元素调用dispatchEvent()方法来触发事件。

//执行位置博客园首页
var objmenu = document.getElementById('nav_menu');
objmenu.onclick = function () {
console.log('menu');
}
document.body.onclick = function () {
console.log('body');
}
var event = document.createEvent('MouseEvent');
event.initMouseEvent('click', true, true, document.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
for (var i = 0; i < 5; i++) {
objmenu.dispatchEvent(event);
}

3. 自定义DOM事件

DOM3中支持自定义DOM事件。要创建新的自定义事件,可以调用document.createEvent()方法,返回的对象有一个initCustomEvent()方法,包含四个参数:

  • type:触发事件的类型;
  • bubbles:事件是否冒泡;
  • cancelable:事件是否可以取消;
  • detail:任意值,保存在event.detail属性中。

最后在DOM元素调用dispatchEvent()方法触发事件。

var objmenu = document.getElementById('nav_menu');
EventUtil.addHandler(objmenu, 'myevent', function (event) {
console.log('menu' + event.detail);
});
EventUtil.addHandler(document.body, 'myevent', function (event) {
console.log('body' + event.detail);
})
if (document.implementation.hasFeature('CustomEvents', '3.0')) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('myevent', true, true, '测试事件detail');
for (var i = 0; i < 5; i++) {
objmenu.dispatchEvent(event);
}
}

读javascript高级程序设计11-事件的更多相关文章

  1. 读javascript高级程序设计00-目录

    javascript高级编程读书笔记系列,也是本砖头书.感觉js是一种很好上手的语言,不过本书细细读来发现了很多之前不了解的细节,受益良多.<br/>本笔记是为了方便日后查阅,仅作学习交流 ...

  2. 读javascript高级程序设计-目录

    javascript高级编程读书笔记系列,也是本砖头书.感觉js是一种很好上手的语言,不过本书细细读来发现了很多之前不了解的细节,受益良多.<br/>本笔记是为了方便日后查阅,仅作学习交流 ...

  3. 读javascript高级程序设计08-引用类型之Global、Math、String

    一.Global 所有在全局作用域定义的属性和方法,都属于Global对象. 1.URI编码: encodeURI():主要用于对整个URI编码.它不会对本身属于URI的特殊字符进行编码. encod ...

  4. 读javascript高级程序设计10-DOM

    一.节点关系 元素的childNodes属性来表示其所有子节点,它是一个NodeList对象,会随着DOM结构的变化动态变化. hasChildNodes():是否有子节点. var headline ...

  5. 读javascript高级程序设计17-在线检测,cookie,子cookie

    一.在线状态检测 开发离线应用时,往往在离线状态时把数据存在本地,而在联机状态时再把数据发送到服务器.html5提供了检测在线状态的方法:navigator.onLine和online/offline ...

  6. 读javascript高级程序设计12-HTML5脚本编程

    一.跨文档消息传递(XDM) 1.发送消息 postMessage(msg,domain)用于发送跨文档消息.第一个参数是要传递的消息内容,第二个参数表示接收方来自哪个域.第二个参数有助于提高安全性, ...

  7. 读javascript高级程序设计13-JSON

    JSON是一个轻量级的数据格式,可以简化表示数据结构的工作量.在实际工作中,我们经常用它来传递数据,不过对于其使用的一些细节还是需要注意的.在ECMAScript5中定义了原生的JSON对象,可以用来 ...

  8. 读javascript高级程序设计15-Ajax,CORS,JSONP,Img Ping

    平时用惯了jQuery.ajax之类的方法,却时常忽略了它背后的实现,本文是学习了AJAX基础及几种跨域解决方案之后的一些收获. 一.AJAX——XMLHttpRequest 谈起Ajax我们都很熟悉 ...

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

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

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

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

随机推荐

  1. vue.js慢速入门(2)

    4.组件使用基础 什么是组件?组件可以理解为可重用的自定义HTML. 可以使用一堆组件来构造大型应用,任意类型的应用界面都可以抽象为一个组件树: 可以把组件代码按照template.style.scr ...

  2. LaTeX插入图片方法 Inserting Images

    Inserting Images Images are essential elements in most of the scientific documents. LATEX provides s ...

  3. JDBC增删改查,PreparedStatement和Statement的区别

    此篇是在上一篇的基础上使用PreparedStatement对象来实现JDBC增删改查的 具体工具类JDBCTools和实现类和配置文件在上一篇Statement对象实现的时候有写. 上一篇地址htt ...

  4. struts2实现文件上传、多文件上传和文件下载

    总结的两个问题,就是struts2上传下载的时候对属性名配置要求非常严格: 第一:上传的时候 private File file; private String fileContentType; pr ...

  5. 使用Redux管理你的React应用

    因为redux和react的版本更新的比较频繁,博客园这里用的redux版本是1.0.1,如果你关心最新版本的使用技巧,欢迎来我的Github查看(https://github.com/matthew ...

  6. paper 104: 彩色图像高速模糊的懒惰算法

    工程及源代码:快速模糊.rar                            图像模糊算法有很多种,我们最常见的就是均值模糊,即取一定半径内的像素值之平均值作为当前点的新的像素值,在一般的工业 ...

  7. C# 刷新页面浏览次数(点击量)+1

    页面视图: <p class="text-center text-muted">文章来源:@ent.Origin 点击量:@ent.Hits <Script La ...

  8. 关于在archlinux中安装virtualbox

    之前安装的时候具体忘记了,现在重新整理一下安装的过程: 1. 安装virtualbox sudo pacman -S virtualbox 安装的过程中因依赖,需要安装提供host模块的包,这里我们安 ...

  9. 机器学习实战-边学边读python代码(3)

    程序清单2-3 归一化特征值: def autoNorm(dataSet): /* >>> barray([[ 1., 2., 3.], [ 2., 3., 4.], [ 10., ...

  10. checkbox样式自定义

    1.使用两张图片(选中和未选中),创建一个选择器. 2.使用checkbox的   drawableLeft  drawableRight  等几个属性把选择器设置进去 3.checkbox的butt ...