【原】javascript事件流
摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊。本文大部分内容参考《javascript高级程序设计第三版》
先来一段书里的原文:
当浏览器发展到第四代时(IE4和Netscape Communicator 4),浏览器团队遇到一个很有意思的问题:页面的哪一部分会拥有特定的事件?想象下在一张纸上有一组同心圆,如果你把手指放在圆心上,那么你的手指指向的不是一个圆,而是一组圆。两家公司的开发团队在看待浏览器事件方面还是一致的。如果你单击了某个按钮,那么同时你也单击了按钮的容器元素,甚至整个页面。
事件流描述的是从页面中接受事件的顺序。但有意思的是,IE和Netscape开发团队居然提出了两个截然相反的事件流概念。
1、IE的事件流是 事件冒泡流,
2、标准的浏览器事件流是 事件捕获流。
不过addEventLister给出了第三个参数同时支持冒泡与捕获,下文将介绍
事件冒泡
ie 的事件流叫事件冒泡,也就是说事件的传播为:从事件开始的具体元素,一级级往上传播到较为不具体的节点。案例如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件冒泡</title>
</head>
<body>
<div>
<p>点我</p>
</div>
</body>
</html>
当我们点击P元素时,事件是这样传播的:
(1) p
(2) div
(3) body
(4) html
(5) document
现代浏览器都支持事件冒泡,IE9、Firefox、Chrome和Safari则将事件一直冒泡到window对象。
事件捕获
Netscape团队提出的另一种事件流叫做事件捕获。它的原理刚好和事件冒泡相反,它的用意在于在事件到达预定目标之前捕获它,而最具体的节点应该是最后才接收到事件的。
比如还是上面的案例,当点击P元素时,事件的传播方向就变成了这样:
(1) document
(2) html
(3) body
(4) div
(5) p
IE9、Firefox、Chrome和Safari目前也支持这种事件流模型,但是有些老版本的浏览器不支持,所以很少人使用事件捕获,而是用事件冒泡的多一点。
DOM事件流
"DOM2级事件"规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。
首先发生的事件捕获,为截获事件提供机会。然后是实际的目标接受事件。最后一个阶段是时间冒泡阶段,可以在这个阶段对事件做出响应。以前面的例子,则会按下图顺序触发事件。
图1-1(图片来源于课本,所以没有上面案例的p标签)
在DOM事件流中,事件的目标在捕获阶段不会接受到事件。这意味着在捕获阶段,事件从document到p后就定停止了。
下一个阶段是处于目标阶段,于是事件在p上发生,并在事件处理中被看成冒泡阶段的一部分。然后,冒泡阶段发生,事件又传播回document。
多数支持DOM事件流的浏览器都实现了一种特定的行为;即使“DOM2级事件”规范明确要求捕获阶段不会涉及事件目标,但IE9、Safari、Chrome、Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件。结果,就是有两个机会在目标对象上操作事件
事件处理程序
事件就是用户或者浏览器自身执行某种动作,比如click、load、mouseover。
而响应某个事件的函数就叫做事件处理程序(事件监听器),事件处理程序的名字以on开头,click=>onclick、load=>onload DOM2提供了两个方法来让我们处理和删除事件处理程序的操作:addEventListener()和removeEventListener
btn.addEventListener(eventType, function () {
}, false);
该方法应用至dom节点
第一个参数为事件名
第二个为事件处理程序
第三个为布尔值,true为事件捕获阶段调用事件处理程序,false为事件冒泡阶段调用事件处理程序
使用例子如下:
var btn = document.getElementById('btn');
btn.addEventListener('click', function () {
alert('事件捕获');
}, true);
btn.addEventListener('click', function () {
alert('事件冒泡');
}, false);
依次弹出“事件捕获”和“事件冒泡”,在这里的第一反应就是,他们有先后顺序吗?
于是我反过来写:
var btn = document.getElementById('btn');
btn.addEventListener('click', function () {
alert('事件冒泡');
}, false);
btn.addEventListener('click', function () {
alert('事件捕获');
}, true);
依次弹出的是:“事件冒泡”和“事件捕获”;到底有没有先后顺序呢?继续往下走
这次是这样的写法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件冒泡</title>
</head>
<body>
<div>
<p id="parEle">我是父元素 <span id="sonEle">我是子元素</span></p>
</div>
</body>
</html>
<script type="text/javascript">
var sonEle = document.getElementById('sonEle');
var parEle = document.getElementById('parEle'); parEle.addEventListener('click', function () {
alert('父级 冒泡');
}, false);
parEle.addEventListener('click', function () {
alert('父级 捕获');
}, true); sonEle.addEventListener('click', function () {
alert('子级冒泡');
}, false);
sonEle.addEventListener('click', function () {
alert('子级捕获');
}, true); </script>
当点击“我是子元素” 时,弹出的顺序是:“父级捕获”--》“子级冒泡”--》“子集捕获”--》“父集冒泡”;
这里可以说明,当点击子元素时,父级的执行顺序是先捕获,后冒泡的。
综合前面的代码,我们可以得出一个小小的结论:
当容器元素及嵌套元素,即在捕获阶段又在冒泡阶段调用事件处理程序时:事件按DOM事件流的顺序执行事件处理程序,也就是如图1-1所示
且当事件处于目标阶段时,事件调用顺序决定于绑定事件的书写顺序,按上面的例子为,先调用冒泡阶段的事件处理程序,再调用捕获阶段的事件处理程序。依次alert出“子集冒泡”,“子集捕获”。
删除一个事件处理程序,用removeEventListener。例:
var btn=document.getElementById('myBtn');
var myFn=function(){
alert(this.id);
}
btn.addEventListener('click',myFn,false);
btn.removeEventListener('click',myFn,false);
注意点:为了最大限度的兼容,大多是情况下都是将事件处理程序添加到事件冒泡阶段。不是特别需要,不建议在事件捕获阶段注册事件处理程序
兼容ie浏览器写法:
ie添加和删除事件处理程序的写法有点小区别,所以用以下代码可以做个兼容性处理:
var EventUtil = {
addHandler: function (el, type, handler) {
if (el.addEventListener) {
el.addEventListener(type, handler, false);
} else {
el.attachEvent('on' + type, handler);
}
},
removeHandler: function (el, type, handler) {
if (el.removeEventListener) {
el.removeEventListerner(type, handler, false);
} else {
el.detachEvent('on' + type, handler);
}
}
};
用法和前面的类似:
EventUtil.addHandler('btn','click',handler);
事件对象
触发dom上的某个事件时,会产生一个事件对象,里面包含着所有和事件有关的信息。
比较常用的有以下几个:
currentTarget 事件处理程序当前正在处理事件的那个元素(始终等于this) preventDefault 取消事件默认行为,比如链接的跳转 stopPropagation 取消事件冒泡 target 事件的目标
兼容ie的事件对象:
var EventUtil = {
addHandler: function (el, type, handler) {
if (el.addEventListener) {
el.addEventListener(type, handler, false);
} else if (el.attachEvent) {
el.attachEvent('on' + type, handler);
} else {
el['on' + type] = handler;
}
},
removeHandler: function (el, type, handler) {
if (el.removeEventListener) {
el.removeEventListerner(type, handler, false);
} else if (el.detachEvent) {
el.detachEvent('on' + type, handler);
} else {
el['on' + type] = null;
}
},
getEvent: function (e) {
return e ? e : window.event;
},
getTarget: function (e) {
return e.target ? e.target : e.srcElement;
},
preventDefault: function (e) {
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
},
stopPropagation: function (e) {
if (e.stopPropagation) {
e.stopPropagation();
} else {
e.cancelBubble = true;
}
}
};
其他
html5事件之 beforeunload
在页面卸载前触发,就像编辑博客园文章未保存是弹出的提示框一样。
html5事件之 DOMContentLoaded事件
页面文档完全加载并解析完毕之后,会触发DOMContentLoaded事件,HTML文档不会等待样式文件,图片文件,子框架页面的加载
EventUtil.addHandler(document,'DOMContentLoaded',function(){
alert('我可以先执行,哈哈')
})
事件委托:
每个函数都是对象,都会占用内存,内存中的对象越多,性能就越差。对事件处理程序过多问题的解决方案就是事件委托。
事件委托利用事件冒泡,只指定一个事件处理程序即可,就可以管理某一个类型的所有事件。例如:
有三个li,都需要一个click事件,此时不需要给每个li都绑定click事件,主要给他的父级 ul增加一个绑定事件即可。这样点击li,利用冒泡,直接触发ul的click,只要判断是哪个li的id
点击即可。而不需要三个li都绑定click事件。
<ul id="myLinks">
<li id="myLi1">text1</li>
<li id="myLi2">text2</li>
<li id="myLi3">text3</li>
</ul>
小小总结,有误之处,欢迎指出
【原】javascript事件流的更多相关文章
- JavaScript事件流原理解析
一.为什么会有这一篇的文章 国庆前几天由于任务比较重,要赶在国庆前把一个进度的任务开发完成,所以也就有点赶,但是却遇到了一个比较奇怪的Bug,导致了任务比预计的延迟了几个小时,对此深表遗憾,所以利用国 ...
- 浅析JavaScript事件流——冒泡
一.什么是事件冒泡流 我们知道事件流指的是从页面中接受事件的顺序. 为了形象理解事件冒泡,可以想象三军主将诸葛亮,在帐内运筹帷幄,眼观六路耳听八方,这时候前方的战事情况就需要靠传令兵来传达,当第一位传 ...
- 深入理解javascript事件流
摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊.本文大部分内容参考<javascript高级程序设计第三版> 先来一段书里的原 ...
- 深入了解javascript事件流
摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊.本文大部分内容参考<javascript高级程序设计第三版> 先来一段书里的原 ...
- JavaScript事件流
什么是JS事件流 早期的IE事件传播方向为由上至下,即从document逐级向下传播到目标元素:而Netscape公司的Netscape Navigator则是朝相反的方向传播, 也就是从目标元素开始 ...
- javaScript事件流是什么?
一.事件 事件是文档或者浏览器窗口中发生的,特定的交互瞬间. 事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字. 事件是javaScript和DOM之间交 ...
- JavaScript事件流--事件冒泡、目标与事件捕获
1.事件冒泡 微软提出了名为事件冒泡的事件流.事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面.也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象. 因 ...
- JavaScript - 事件流
事件流 事件冒泡就是事件沿DOM树向上传播,在没一级节点上都会发生,直至传播到document对象. 事件捕获正好相反,但是老版本的浏览器不支持,因此很少有人使用事件捕获. 事件处理程序 HTMl 事 ...
- javascript 事件流及应用
当页面元素触发事件的时候,该元素的容器以及整个页面都会按照特定顺序发生该元素的触发 事件,事件传播的顺序叫做事件流 1.事件流的分类: A.冒泡型事件(所有浏览器都支持) 由明确的事件源到最不确定 ...
随机推荐
- 中断ORACLE数据库关闭进程导致错误案例
昨晚下班的时候,我准备关闭本机的虚拟机上的ORACLE数据库后准备下班,但是由于我SecureCRT开了多个窗口,结果一不小心,疏忽之下在一个生产服务器上执行了shutdown immediate命令 ...
- Unable to determine if the owner (Domain\UserName) of job JOB_NAME has server access
早上巡检的的时候,发现一数据库的作业报如下错误(作业名等敏感信息已经替换),该作业的OWNER为一个域账号: JOB RUN: 'JOB_NAME' was run on 2016-6-1 at 7: ...
- Solr图形化界面banana:除Hue之外的选择
最近Hue+Solr 方案原型验证有了一些进展.正好也收到了Google的大数据专家Sam的来件询问进展,我答复如下: Sam, 你好. 已经把Kafka+flume+solr的实时索引搭建起来了, ...
- Linux的概念与体系
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我在这一系列文章中阐述Linux的基本概念.Linux操作系统继承自UNIX.一个 ...
- 利用oneproxy部署mysql数据库的读写分离
实验系统:CentOS 6.6_x86_64 实验前提:防火墙和selinux都关闭 实验说明:本实验共有4台主机,IP分配如拓扑 实验软件:mariadb-10.0.20 oneproxy-rhel ...
- 整理几篇比较好的AndroidUI动画开发文章
第一篇,写的比较详细,新手可以看得懂: http://www.360doc.com/content/16/0128/08/30422106_531162539.shtml
- 游戏测评-桥梁建造系Poly Bridge破力桥?游戏测评
最近在b站看到了谜之声的视频:大家来造桥吧! 实在是太搞笑了,看到是一款新出不久还未正式发行的游戏,兴致一来便入手玩了玩.顺手也就写下了这篇测评. POLY BRIDGE 对这个游戏名怎么起个有趣的中 ...
- NOIP2013pj车站分级[拓扑排序]
题目描述 一条单向的铁路线上,依次有编号为 1, 2, …, n 的 n 个火车站.每个火车站都有一个级 别,最低为 1 级.现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车 次停靠了 ...
- NYOJ 485
A*B Problem 描述 设计一个程序求出A*B,然后将其结果每一位相加得到C,如果C的位数大于等于2,继续将C的各位数相加,直到结果是个一位数k. 例如: 6*8=48: 4+8=12: 1+2 ...
- NYOJ 70
描述:给定两个数n,m,其中m是一个素数. 将n(0<=n<=2^31)的阶乘分解质因数,求其中有多少个m. 注:^为求幂符号. 输入: 第一行是一个整数s(0<s<=100) ...