JS Event事件流(冒泡机制、捕获机制、事件绑定)
1.事件流
事件流:从页面中接收事件的顺序。也就是说当一个事件产生时,这个事件的传播过程,就是事件流。
- IE的事件流
IE中的事件流叫事件冒泡;事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档)。对于html来说,就是当一个元素产生了一个事件,它会把这个事件传递给它的父元素,父元素接收到了之后,还要继续传递给它的上一级元素,就这样一直传播到document对象(亲测现在的浏览器到window对象,只有IE8及下不这样);
再多说一句,现在的浏览器默认是采用的是事件冒泡;在DOM0级方法绑定事件只能是事件冒泡,不能设置;在DOM2级你可以设置是用事件冒泡还是事件捕获(下面说);
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件冒泡</title>
<style type="text/css">
#child{background: red;width: 50px;height: 50px;}
#father{width: 100px;height: 100px;background: green;}
#grandparent{
width: 150px;height: 150px;background: black;margin: 100px auto 0;}
</style>
</head>
<body>
<div id="grandparent">
<div id="father">
<div id="child"></div>
</div>
</div>
</body>
<script type="text/javascript">
var grandparent=document.getElementById("grandparent");
var parent=document.getElementById("father");
var child=document.getElementById('child');
var body=document.body;
var html=document.getElementsByTagName("html")[0];
child.onclick=function(){
console.log("我是儿子");
}
parent.onclick=function(){
console.log("我是父亲");
}
grandparent.onclick=function(){
console.log("我是爷爷");
}
window.onclick=function(){
console.log("我是window");
}
document.onclick=function(){
console.log("我是document");
}
html.onclick=function(){
console.log("我是html");
}
body.onclick=function(){
console.log("我是body");
}
</script>
</html>
当我点击红色部分
会打印这样:
我测试了(PS:我用的都是最新版的)chrome,firefox,opera,IE11,IE10,IE9都是这个结果,也就是说现在都冒泡到window对象,不仅仅是到document对象,但是IE8及之前的就冒泡到document就结束了;
这就是事件冒泡,它会把你这个click事件,一级一级的向上传递,如果相应的元素也绑定click事件处理程序(这里强调是click事件,如果你是给绑定了其它事件,那没用),那么它的这个事件处理程序也会执行,也就产生了上面的结果了;
形象的就是跟水里的鱼吐泡泡似的,慢慢的向上传递;
- 事件捕获
事件捕获是网景(Netscape)提出来的,事件捕获是不太具体的元素应该更早接受到事件,而最具体的节点应该最后接收到事件。他们的用意是在事件到达目标之前就捕获它;也就是跟冒泡的过程正好相反,以html的click事件为例,document对象(DOM级规范要求从document开始传播,但是现在的浏览器是从window对象开始的)最先接收到click事件的然后事件沿着DOM树依次向下传播,一直传播到事件的实际目标;我测试了一下(我用的都是最新的浏览器),chrome,opera,firefox,IE11到IE9都支持事件捕获。
代码等着我在下面讲DOM事件流再一块说明;
- DOM事件流
DOM2级中规定了事件流要包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。这是W3C采用了他们两家的事件监听机制。(说点题外话,w3c中的很多标准就是这样,浏览器厂商有很多自己的私有解决问题方式,好用的就被W3c采纳了)DOM2级还规定,实际发生事件的元素在捕获阶段不能接收到事件。我们就以上面的事件冒泡时的代码说明这个过程:按照标准是这样的,当一个元素产生了事件,事件是从document到html再到body再到DIV爷爷再到DIV爸爸,这时候捕获阶段就应该停止了,再进入下一个阶段“处于目标阶段”,然后是从DIV爸爸到DIV爷爷再到body再到html再到document,这就是事件冒泡阶段;实际上我们把处于目标阶段即第二阶段看作是冒泡阶段的一部分,即冒泡的开始;实际上是怎么样的呢?先上代码,还是前面的代码只是改了一下js代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件冒泡</title>
<style type="text/css">
#child{ background: red; width:50px; height:50px; }
#father{ width:100px; height:100px; background:green; }
#grandparent{ width:150px; height:150px; background:black; margin:100px auto 0; }
</style>
</head>
<body>
<div id="grandparent">
<div id="father">
<div id="child"></div></div>
</div>
</body>
<script type="text/javascript">
var grandparent = document.getElementById("grandparent");
var parent = document.getElementById("father");
var child = document.getElementById('child');
var html = document.getElementsByTagName("html")[0];
var body = document.body;
grandparent.addEventListener("click",function ()
{console.log("I am capturing grandparent"); },true);
grandparent.addEventListener("click",function () {console.log("I am grandparent"); },false);
parent.addEventListener("click",function() {console.log("I am parent"); },false);
parent.addEventListener("click",function() { console.log("I am capturing parent"); },true);
child.addEventListener("click",function() { console.log("I am capturing child"); },true);
child.addEventListener("click",function() { console.log("I am child"); },false);
body.addEventListener("click",function() { console.log("I am body"); },false);
body.addEventListener("click",function() { console.log("I am capturing body"); },true);
html.addEventListener("click",function() { console.log("I am capturing html"); },true);
html.addEventListener("click",function() { console.log("I am html"); },false);
document.addEventListener("click",function() { console.log("I am capturing document"); },true);
document.addEventListener("click",function() { console.log("I am document"); },false);
window.addEventListener("click",function() {console.log("I am window"); },false);
window.addEventListener("click",function() {console.log("I am capturing window"); },true);
</script></html>
代码有点多见谅了!也是为了最能说明问题!
打印是这样的:
这是我点击最里面DIV儿子元素所发生的情形,可以看出捕获阶段也能触发目标元素上的事件,而不仅仅是在冒泡阶段;并且还是从window开始,到最后再以window对象结束,浏览器厂商就是任性,不把W3c看在眼里。你的标准我想实现就实现不想就不实现;
当我把DIV爷爷的事件绑定方式换成DOM0级的方式,其他的保持不变,即
grandparent.onclick = function() { console.log("我是在哪个阶段发生呢?") }
是这样打印的
再次说明了我上面在IE事件流中强调的,用DOM0级绑定事件时,事件只发生冒泡的阶段;
1. type:事件的类型,如onlick中的click;
2. srcElement/target:事件源,就是发生事件的元素;
3. button:声明被按下的鼠标键,整数,1代表左键,2代表右键,4代表中键,如果按下多个键,酒把这些值加起来,所以3就代表左右键同时按下;(firefox中 0代表左键,1代表中间键,2代表右键)
4. clientX/clientY:事件发生的时候,鼠标相对于浏览器窗口可视文档区域的左上角的位置;(在DOM标准中,这两个属性值都不考虑文档的滚动情况,也就是说,无论文档滚动到哪里,只要事件发生在窗口左上角,clientX和clientY都是 0,所以在IE中,要想得到事件发生的坐标相对于文档开头的位置,要加上
document.body.scrollLeft和 document.body.scrollTop)
5. offsetX,offsetY/layerX,layerY:事件发生的时候,鼠标相对于源元素左上角的位置;
6. x,y/pageX,pageY:检索相对于父元素鼠标水平坐标的整数;
7. altKey,ctrlKey,shiftKey等:返回一个布尔值;
8. keyCode:返回keydown和keyup事件发生的时候按键的代码,以及keypress 事件的Unicode字符;(firefox2不支持 event.keycode,可以用 event.which替代 )
9. fromElement,toElement:前者是指代mouseover事件中鼠标移动过的文档元素,后者指代mouseout事件中鼠标移动到的文档元素;
10. cancelBubble:一个布尔属性,把它设置为true的时候,将停止事件进一步起泡到包容层次的元素;(e.cancelBubble = true; 相当于 e.stopPropagation();)
11. returnValue:一个布尔属性,设置为false的时候可以组织浏览器执行默认的事件动作;(e.returnValue = false; 相当于 e.preventDefault();)
12. attachEvent(),detachEvent()/addEventListener(),removeEventListener:为制定 DOM对象事件类型注册多个事件处理函数的方法,它们有两个参数,第一个是事件类型,第二个是事件处理函数。在
attachEvent()事件执行的时候,this关键字指向的是window对象,而不是发生事件的那个元素;
13. screenX、screenY:鼠标指针相对于显示器左上角的位置,如果你想打开新的窗口,这两个属性很重要;
一些说明:
1. event代表事件的状态,例如触发event对象的元素、鼠标的位置及状态、按下的键等等;
2. event对象只在事件发生的过程中才有效。
firefox里的event跟IE里的不同,IE里的是全局变量,随时可用;firefox里的要用参数引导才能用,是运行时的临时变量。
在IE/Opera中是window.event,在Firefox中是event;而事件的对象,在IE中是 window.event.srcElement,在Firefox中是event.target,Opera中两者都可用。
3. 下面两句效果相同
var evt = (evt) ? evt : ((window.event) ? window.event : null);
var evt = evt || window.event; // firefox下window.event为null, IE下event为null
4. IE中事件的起泡
IE中事件可以沿着包容层次一点点起泡到上层,也就是说,下层的DOM节点定义的事件处理函数,到了上层的节点如果还有和下层相同事件类型的事件处理函数,那么上层的事件处理函数也会执行。例如, div 标签包含了 a ,如果这两个标签都有onclick事件的处理函数,那么执行的情况就是先执行标签 a 的onclick事件处理函数,再执行 div 的事件处理函数。如果希望的事件处理函数执行完毕之后,不希望执行上层的 div 的onclick的事件处理函数了,那么就把cancelBubble设置为true即可。
JS Event事件流(冒泡机制、捕获机制、事件绑定)的更多相关文章
- react第五单元(事件系统-原生事件-react中的合成事件-详解事件的冒泡和捕获机制)
第五单元(事件系统-原生事件-react中的合成事件-详解事件的冒泡和捕获机制) 课程目标 深入理解和掌握事件的冒泡及捕获机制 理解react中的合成事件的本质 在react组件中合理的使用原生事件 ...
- 初始js闭包&事件的冒泡和捕获&EVENT对象
一.初识闭包 function a(){ var n = 0; this.inc = function () { n++; console.log(n); }; } var ...
- 整理之DOM事件阶段、冒泡与捕获、事件委托、ie事件和dom模型事件、鼠标事件
整理之DOM事件阶段 本文主要解决的问题: 事件流 DOM事件流的三个阶段 先理解流的概念 在现今的JavaScript中随处可见.比如说React中的单向数据流,Node中的流,又或是今天本文所讲的 ...
- 事件冒泡与捕获&事件托付
设想这样一种情况 一个div里面有个span元素 ,当鼠标单击span时,这个事件算是谁的? div还是span? 准确的说两个都触发了,这种认可大家都允许,事实就是这种, 第二个问题来了,这个事件 ...
- 从零开始的全栈工程师——js篇2.20(事件对象 冒泡与捕获)
一.复习 面向对象 1)单例模式 2)工厂模式 3)构造函数 ①类js天生自带的类 基类object function array number math boolean date regexp st ...
- W3C标准冒泡、捕获机制
(一) 捕获和冒泡如何相互影响 我们来做几个任务吧! 有一个前提,#parent为标签,#child为子标签,他们是嵌套关系支线任务1 //捕获模式 document.getElementById(' ...
- JavaScript权威设计--事件冒泡,捕获,事件句柄,事件源,事件对象(简要学习笔记十八)
1.事件冒泡与事件捕获 2.事件与事件句柄 3.事件委托:利用事件的冒泡技术.子元素的事件最终会冒泡到父元素直到跟节点.事件监听会分析从子元素冒泡上来的事件. 事件委托的好处: 1.每个函 ...
- 浅析JavaScript事件流——冒泡
一.什么是事件冒泡流 我们知道事件流指的是从页面中接受事件的顺序. 为了形象理解事件冒泡,可以想象三军主将诸葛亮,在帐内运筹帷幄,眼观六路耳听八方,这时候前方的战事情况就需要靠传令兵来传达,当第一位传 ...
- js事件(一)之事件流
1.事件流定义 事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件,这个传播过程即DOM事件流. 事件传播的顺序对应浏览器的两种事件流模型:捕获型事件流和冒泡型事 ...
- JS事件流理解
事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字. 事件是javaScript和DOM之间的桥梁. 你若触发,我便执行--事件发生,调用它的处理函数执行相 ...
随机推荐
- Android IPC机制全解析<二>
在AIDL文件中并不是所有的数据类型都可以使用,AIDL支持的数据类型如下: 基本数据类型(int.long.char.boolean.double等) String和CharSequence Lis ...
- let 和 const 关键字
看了阮老师的ES6入门再加上自己的一些理解整理出的学习笔记 let关键字 跟var相比,不会提升为全局变量,始终是块级作用域{} 注意点: 1: 不能在同一个块级作用域内声明同名变量 2: (如果当前 ...
- less补充函数
1.ceil():向上取整2.floor():向下取整3.percentage():将浮点数转换成百分比3.round():四舍五入4.sqrt():平方根5.abs():绝对值6.pow():乘方运 ...
- webscoket实战之利用httpsession定向推送
webscoket实战之利用httpsession定向推送 开发框架 springboot 场景 在利用websocket主动推送信息给客户端的过程中,经常会遇到一个普遍需求,就是推送的消息要定向推送 ...
- 一款好用的jquery评分插件
一.使用说明 1.jQuery评分插件的功能: 图标显示用户评分,更美观 可实时点击,切换评分 返回用户评分,记录用户评分 实现类似下图效果 2.优点: 美观,方便 3.缺点: 只能用于jquery开 ...
- MapReduce中一次reduce方法的调用中key的值不断变化分析及源码解析
摘要:mapreduce中执行reduce(KEYIN key, Iterable<VALUEIN> values, Context context),调用一次reduce方法,迭代val ...
- Maven的下载,安装,配置,测试,初识
1:Maven官网:http://maven.apache.org/ Maven远程仓库:http://search.maven.org/ 2:Maven是一个采用纯Java编写的开源项目管理工具,M ...
- 基于jQuery的自定义插件:实现整屏分页转换的功能
动态创建jQuery插件 一.实现功能: 1.基本功能:自适应式整屏分页功能的实现 2.通过鼠标点击标签页转换分页,支持键盘上下左右键的转换分页,同样支持 鼠标滚轮上下滑动转换分页 3.切屏时的动画效 ...
- Java核心技术 卷I chapter05 继承
2017年4月10日19:41:44 仅仅用于打好基础 1. 在Java中,所有的继承都是公有继承,而没有C++中的私有继承和保护继承! 2.关键字super的使用方法: (1) 子类中想调用父类中的 ...
- 四、I/O
九.什么是I/O: 9.1.在Windows程序中,基础的运行单位为线程,为每一个线程分配一个处理器,可以让系统执行多个操作, 9.2.当线程进行一个I/O操作时,会被挂起,从而影响性能,为了解决这类 ...