js事件流 事件捕获 及时间冒泡详解
Javascript与HTML之间的交互是通过事件实现。
一、事件流
事件,是文档或浏览器窗口中发生的一些特定的交互瞬间。事件流,描述的是页面中接受事件的顺序。IE9,chrome,Firefox,Opera,Safari均实现了DOM2级规范中定义的标准DOM事件,而IE8和IE8以下版本仍然保留专有的事件处理方式。
事件冒泡
事件冒泡是由IE开发团队提出来的,即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播。

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Event Bubbling Example</title>
</head>
<style type="text/css">
#myDiv{
width:100px;
height:100px;
background-color:#FF0000;
}
</style>
<body>
<div id="myDiv"></div>
</body>
</html>

当用户点击了<div>元素,click事件将按照<div>—><body>—><html>—>document的顺序进行传播。若在<div>和<body>上都定义了click事件,如下:

<script type="text/javascript">
var div=document.getElementById("myDiv");
div.onclick=function(event){
alert("div");
};
document.body.onclick=function(event){
alert("body");
};
</script>

点击<div>,将先输出“div”,再输出“body”。
IE9,chrome,Firefox,Opera,Safari都支持事件冒泡,并将事件冒泡到window对象。
事件捕获
事件捕获是由Netscape Communicator团队提出来的,是先由最上一级的节点先接收事件,然后向下传播到具体的节点。当用户点击了<div>元素,采用事件捕获,则click事件将按照document—><html>—><body>—><div>的顺序进行传播。
若在<div>和<body>上都定义了click事件,如下:

<script type="text/javascript">
var div=document.getElementById("myDiv");
div.addEventListener("click",function(event){
alert("div");
},true);
document.body.addEventListener("click",function(event){
alert("body");
},true); </script>

(注:addEventListener具体使用见本文DOM2级事件处理)
点击<div>,将先输出“body”,再输出“div”。
IE9,chrome,Firefox,Opera,Safari都支持事件捕获,但是IE8和IE8以下的版本只支持事件冒泡。尽管DOM2规范要求事件应该从document对象开始传播,但是现在的浏览器实现都是从window对象开始捕获事件。
DOM事件流
"DOM2级事件”规定的事件流包含三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,然后是实际的目标接收到事件,最后阶段是冒泡阶段。以上面的HTML页面为例,单击<div>元素将按照下图触发事件:

若在<div>和<body>上都定义了click事件,如下:

<script type="text/javascript">
var div=document.getElementById("myDiv");
div.onclick=function(event){
alert("div");
};
document.body.addEventListener("click",function(event){
alert("event bubble");
},false);
document.body.addEventListener("click",function(event){
alert("event catch");
},true); </script>

点击<div>,将先输出“event catch”,再输出“div”,最后输出“event bubble”。
二、事件处理程序
事件是用户或浏览器自身执行的某种动作,而响应某个事件的函数叫做事件处理程序。HTML事件处理程序、DOM0级事件处理程序和IE事件处理程序均以“on”开头,DOM2级事件处理程序不需要加“on”。
HTML事件处理程序
通过将事件作为HTML元素的属性来实现,包含以下两种方法:
| 1 | <inputtype="button" value="confirm" onclick="alert('confirm')" /> | 
或者调用其他地方定义的脚本:
<script type="text/javascript">
function showMessage() {
alert("confirm");
}
</script>
<input type="button" value="confirm" onclick="showMessage()"/>
(注:函数定义必须放在调用之前)
DOM0级事件处理程序
通过Javascript指定事件处理程序的传统方式,所有浏览器均支持。每个元素(包括window,document)都有自己的事件处理程序属性,但是必须在DOM节点加载完之后才会有效。如下所示:
<script type="text/javascript">
var div = document.getElementById("myDiv");
div.onclick = function(event) {
alert("div");
};
</script>
使用DOM0级方法指定的事件处理程序被认为是元素的方法,在元素的作用域中运行。this引用当前元素,如下:
<script type="text/javascript">
var div = document.getElementById("myDiv");
div.onclick = function(event) {
alert(this.id);
};
</script>
输出“myDiv”。
删除通过DOM0级方法指定的事件处理程序:div.onclick=null;
DOM2级事件处理程序
IE9,chrome,Firefox,Opera,Safari均实现了DOM2级事件处理程序,绑定事件方法addEventListener()接收三个参数:事件名称,事件处理函数和一个布尔值。布尔值为true,则表示在捕获阶段调用事件处理程序;如果为false,则表示在冒泡阶段调用事件处理程序。addEventListener允许在同一个元素上添加多个事件处理程序,如下所示:

<script type="text/javascript">
var div = document.getElementById("myDiv");
div.addEventListener("click", function(event) {
alert("event bubble");
}, false);
div.addEventListener("click", function(event) {
alert("event catch");
}, true);
</script>

先输出“event bubble”,后输出“event catch”,说明addEvenListener绑定的处理程序执行顺序和绑定顺序相同。
通过DOM2级事件处理程序指定的方法,this也引用当前元素,如下:
<script type="text/javascript">
var div = document.getElementById("myDiv");
div.addEventListener("click", function(event) {
alert(this.id);
}, false);
</script>
输出“myDiv”。
删除DOM2级事件处理程序,采用removeEventListener(),删除时传入的参数必须和绑定时传入的参数相同,不能传入匿名函数。如下所示:

<script type="text/javascript">
var div = document.getElementById("myDiv");
var handler=function(event){
alert("delete");
};
div.addEventListener("click",handler,false);
div.removeEventListener("click",handler,false);
</script>

IE事件处理程序
IE8和IE8以下的版本不支持addEventListener(),而是采用attachEvent()来实现事件绑定。目前只有IE和Opera支持attachEvent()。IE9支持addEventListener(),同时也兼容IE8的attachEvent()方法,但是IE9和IE8对attachEvent()的实现有点不同。如下所示:

<script type="text/javascript">
var div = document.getElementById("myDiv");
div.attachEvent("onclick", function(event) {
alert("1");
});
div.attachEvent("onclick", function(event) {
alert("2");
});
</script>

IE9和IE10先输出“1”,再输出“2”,而IE8和IE7先输出“2”,再输出“1”。
删除IE事件处理程序,采用detachEvent(),删除时传入的参数必须和绑定时传入的参数相同,不能传入匿名函数。如下所示:

<script type="text/javascript">
var div = document.getElementById("myDiv");
var handler = function(event) {
alert("delete");
};
div.attachEvent("onclick",handler);
div.detachEvent("onclick",handler);
</script>

总结:attachEvent()采用冒泡方式,而addEventListener()可以采用冒泡或事件捕获方式。
先按由上往下的顺序执行事件捕获的执行程序,再执行目标元素的执行程序,最后按由下往上的顺序执行冒泡事件。代码如下所示:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Event Bubbling Example</title>
</head>
<style type="text/css">
#child {
width: 100px;
height: 100px;
background-color: #FF0000;
}
</style>
<body>
<div id="parent">
<div id="child"></div>
</div>
</body>
<script type="text/javascript">
var parent = document.getElementById("parent");
var child = document.getElementById("child");
child.onclick = function(event) {
alert("child");
};
document.body.addEventListener("click", function(event) {
alert("body:event bubble");
}, false);
parent.attachEvent("onclick", function(event) {
alert("parent:event bubble");
});
document.body.addEventListener("click", function(event) {
alert("body:event catch");
}, true);
parent.addEventListener("click", function(event) {
alert("parent:event catch");
}, true);
</script>
</html>

输出顺序:body:event catch—>parent:event catch—>child—>parent:event bubble—>body:event bubble
摘自:https://www.cnblogs.com/linxuehan/p/3623760.html
js事件流 事件捕获 及时间冒泡详解的更多相关文章
- JavaScript的事件、DOM模型、事件流模型以及内置对象详解(三)
		JS中的事件 JS中的事件分类 1.鼠标事件: click/dbclick/mouseover/mouseout 2.HTML事件: onload/onunload/onsubmit/onresize ... 
- JavaScript 进阶教程一 JavaScript 中的事件流 - 事件冒泡和事件捕获
		先看下面的示例代码: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Jav ... 
- [概念] js的函数节流和throttle和debounce详解
		js的函数节流和throttle和debounce详解:同样是实现了一个功能,可能有的效率高,有的效率低,这种现象在高耗能的执行过程中区分就比较明显.本章节一个比较常用的提高性能的方式,通常叫做&qu ... 
- Android View 的绘制流程之 Layout 和 Draw 过程详解 (二)
		View 的绘制系列文章: Android View 的绘制流程之 Measure 过程详解 (一) Android View 绘制流程之 DecorView 与 ViewRootImpl 在上一篇 ... 
- SQL Server时间粒度系列----第3节旬、月时间粒度详解
		本文目录列表: 1.SQL Server旬时间粒度2.SQL Server月有关时间粒度 3.SQL Server函数重构 4.总结语 5.参考清单列表 SQL Server旬时间粒度 ... 
- SQL Server时间粒度系列----第4节季、年时间粒度详解
		本文目录列表: 1.SQL Server季时间粒度2.SQL Server年时间粒度 3.总结语 4.参考清单列表 SQL Serve季时间粒度 季时间粒度也即是季度时间粒度.一年每3 ... 
- js实现的新闻列表垂直滚动实现详解
		js实现的新闻列表垂直滚动实现详解:新闻列表垂直滚动效果在大量的网站都有应用,有点自然是不言而喻的,首先由于网页的空间有限,使用滚动代码可以使用最小的空间提供更多的信息量,还有让网页有了动态的效果,更 ... 
- main.js index.html与app.vue三者关系详解
		main.js index.html与app.vue三者关系详解 2019年01月23日 11:12:15 Pecodo 阅读数 186 main.js与index.html是nodejs的项目启 ... 
- JavaScript事件流--事件冒泡、目标与事件捕获
		1.事件冒泡 微软提出了名为事件冒泡的事件流.事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面.也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象. 因 ... 
随机推荐
- Yarn 的日志聚集功能配置使用
			需要 hadoop 的安装目录/etc/hadoop/yarn-site.xml 中进行配置 配置内容 <property> <name>yarn.log-aggregati ... 
- 【C#】取整函数Math.Round、Math.Ceiling和Math.Floor区别
			Math.Round 原则: 四舍六入五取偶. 也就是说 0.1-0.4为0 0.5为0 0.6-0.9为1 1.5为2 Math.Ceiling 原则: 有小数就加1 0.1 = 1 Math.Fl ... 
- MySQL中查询时间最大的一条记录
			在项目中要查询用户最近登录的一条记录的 ip 直接写如下 SQL: SELECT ip,MAX(act_time) FROM users_login GROUP BY login_id; 但是这样是取 ... 
- shell中的${},##, %% , :- ,:+, ? 的使用
			假设我们定义了一个变量为:file=/dir1/dir2/dir3/my.file.txt 可以用${ }分别替换得到不同的值:${file#*/}:删掉第一个/ 及其左边的字符串:dir1/dir2 ... 
- JavaScript重点知识(二)
			三.JS的API 3.1知识点(DOM) 1)DOM本质 将html结构化成浏览器和JS可识别可操作的东西 2)变量计算---强制类型转换 获取DOM节点 Attribute(对html标签属性的修改 ... 
- 【三十五】thinkphp之视图
			1.模板定义 视图属于mvc中的v.一般是html结合php获取的数据提供给用户使用. 每个模板的文件都是独立的(文件名与控制器名称必须一样) 默认的模板文件规则是视图目录/[模板主题]控制器/操作名 ... 
- isnull和sum的关系
			这是我刚刚写存储过程的时候意识到的一个问题!!! 先问大家这样一个问题,print 100+null 等于多少? 在一组数据统计的过程中,只要使用到sum函数,就必须使用isnull函数包含起来,因 ... 
- [osg][osgEarth][osgGA][原]  EarthManipulator------基于oe的相机漫游器(浅析)
			知识基础:osg漫游器基础 class OSGEARTHUTIL_EXPORT EarthManipulator : public osgGA::CameraManipulator EarthMani ... 
- 扩展EF的Fluent API中的 OnModelCreating方法 实现全局数据过滤器
			1.生成过滤的表达式目录树 protected virtual Expression<Func<TEntity, bool>> CreateFilterExpression&l ... 
- split函数
			b="aa,:bb:c,c"a1,a2,a3=b.split(":") #以:为分隔符,分成3个字符串 
