摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊。本文大部分内容参考《javascript高级程序设计第三版》

先来一段书里的原文:

  当浏览器发展到第四代时(IE4和Netscape Communicator 4),浏览器团队遇到一个很有意思的问题:页面的哪一部分会拥有特定的事件?想象下在一张纸上有一组同心圆,如果你把手指放在圆心上,那么你的手指指向的不是一个圆,而是一组圆。两家公司的开发团队在看待浏览器事件方面还是一致的。如果你单击了某个按钮,那么同时你也单击了按钮的容器元素,甚至整个页面。

 事件流描述的是从页面中接受事件的顺序。但有意思的是,IE和Netscape开发团队居然提出了两个截然相反的事件流概念。

  1、IE的事件流是 事件冒泡流,

   2、标准的浏览器事件流是 事件捕获流。

不过addEventLister给出了第三个参数同时支持冒泡与捕获,下文将介绍

事件冒泡

ie 的事件流叫事件冒泡,也就是说事件的传播为:从事件开始的具体元素,一级级往上传播到较为不具体的节点。案例如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>事件冒泡</title>
  6. </head>
  7. <body>
  8. <div>
  9. <p>点我</p>
  10. </div>
  11. </body>
  12. </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及更高版本都会在捕获阶段触发事件对象上的事件。结果,就是有两个机会在目标对象上操作事件

事件处理程序

  1. 事件就是用户或者浏览器自身执行某种动作,比如clickloadmouseover
    而响应某个事件的函数就叫做事件处理程序(事件监听器),事件处理程序的名字以on开头,click=>onclickload=>onload
  2.  
  3. DOM2提供了两个方法来让我们处理和删除事件处理程序的操作:addEventListener()和removeEventListener
1
2
3
4
5
6
7
btn.addEventListener(eventType, function () {
}, false);
 
该方法应用至dom节点
第一个参数为事件名
第二个为事件处理程序
第三个为布尔值,true为事件捕获阶段调用事件处理程序,false为事件冒泡阶段调用事件处理程序

使用例子如下:

  1. var btn = document.getElementById('btn');
  2. btn.addEventListener('click', function () {
  3. alert('事件捕获');
  4. }, true);
  5. btn.addEventListener('click', function () {
  6. alert('事件冒泡');
  7. }, false);

依次弹出“事件捕获”和“事件冒泡”,在这里的第一反应就是,他们有先后顺序吗?

于是我反过来写:

  1. var btn = document.getElementById('btn');
  2. btn.addEventListener('click', function () {
  3. alert('事件冒泡');
  4. }, false);
  5. btn.addEventListener('click', function () {
  6. alert('事件捕获');
  7. }, true);

依次弹出的是:“事件冒泡”和“事件捕获”;到底有没有先后顺序呢?继续往下走

这次是这样的写法:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>事件冒泡</title>
  6. </head>
  7. <body>
  8. <div>
  9. <p id="parEle">我是父元素 <span id="sonEle">我是子元素</span></p>
  10. </div>
  11. </body>
  12. </html>
  13. <script type="text/javascript">
  14. var sonEle = document.getElementById('sonEle');
  15. var parEle = document.getElementById('parEle');
  16.  
  17. parEle.addEventListener('click', function () {
  18. alert('父级 冒泡');
  19. }, false);
  20. parEle.addEventListener('click', function () {
  21. alert('父级 捕获');
  22. }, true);
  23.  
  24. sonEle.addEventListener('click', function () {
  25. alert('子级冒泡');
  26. }, false);
  27. sonEle.addEventListener('click', function () {
  28. alert('子级捕获');
  29. }, true);
  30.  
  31. </script>

当点击“我是子元素” 时,弹出的顺序是:“父级捕获”--》“子级冒泡”--》“子集捕获”--》“父集冒泡”;

这里可以说明,当点击子元素时,父级的执行顺序是先捕获,后冒泡的。

  综合前面的代码,我们可以得出一个小小的结论:

  当容器元素及嵌套元素,即在捕获阶段又在冒泡阶段调用事件处理程序时:事件按DOM事件流的顺序执行事件处理程序,也就是如图1-1所示

  且当事件处于目标阶段时,事件调用顺序决定于绑定事件的书写顺序,按上面的例子为,先调用冒泡阶段的事件处理程序,再调用捕获阶段的事件处理程序。依次alert出“子集冒泡”,“子集捕获”。

删除一个事件处理程序,用removeEventListener。例:

  1. var btn=document.getElementById('myBtn');
  2. var myFn=function(){
  3. alert(this.id);
  4. }
  5. btn.addEventListener('click',myFn,false);
  6. btn.removeEventListener('click',myFn,false);

注意点:为了最大限度的兼容,大多是情况下都是将事件处理程序添加到事件冒泡阶段。不是特别需要,不建议在事件捕获阶段注册事件处理程序

兼容ie浏览器写法:

ie添加和删除事件处理程序的写法有点小区别,所以用以下代码可以做个兼容性处理:

  1. var EventUtil = {
  2. addHandler: function (el, type, handler) {
  3. if (el.addEventListener) {
  4. el.addEventListener(type, handler, false);
  5. } else {
  6. el.attachEvent('on' + type, handler);
  7. }
  8. },
  9. removeHandler: function (el, type, handler) {
  10. if (el.removeEventListener) {
  11. el.removeEventListerner(type, handler, false);
  12. } else {
  13. el.detachEvent('on' + type, handler);
  14. }
  15. }
  16. };

用法和前面的类似:

  1. EventUtil.addHandler('btn','click',handler);

事件对象

触发dom上的某个事件时,会产生一个事件对象,里面包含着所有和事件有关的信息。

比较常用的有以下几个:

currentTarget   事件处理程序当前正在处理事件的那个元素(始终等于this)
 
preventDefault  取消事件默认行为,比如链接的跳转
 
stopPropagation 取消事件冒泡
 
target  事件的目标

  

兼容ie的事件对象:

  1. var EventUtil = {
  2. addHandler: function (el, type, handler) {
  3. if (el.addEventListener) {
  4. el.addEventListener(type, handler, false);
  5. } else if (el.attachEvent) {
  6. el.attachEvent('on' + type, handler);
  7. } else {
  8. el['on' + type] = handler;
  9. }
  10. },
  11. removeHandler: function (el, type, handler) {
  12. if (el.removeEventListener) {
  13. el.removeEventListerner(type, handler, false);
  14. } else if (el.detachEvent) {
  15. el.detachEvent('on' + type, handler);
  16. } else {
  17. el['on' + type] = null;
  18. }
  19. },
  20. getEvent: function (e) {
  21. return e ? e : window.event;
  22. },
  23. getTarget: function (e) {
  24. return e.target ? e.target : e.srcElement;
  25. },
  26. preventDefault: function (e) {
  27. if (e.preventDefault) {
  28. e.preventDefault();
  29. } else {
  30. e.returnValue = false;
  31. }
  32. },
  33. stopPropagation: function (e) {
  34. if (e.stopPropagation) {
  35. e.stopPropagation();
  36. } else {
  37. e.cancelBubble = true;
  38. }
  39. }
  40. };

其他

html5事件之 beforeunload

在页面卸载前触发,就像编辑博客园文章未保存是弹出的提示框一样。

html5事件之 DOMContentLoaded事件

支持页面下载前添加事件,而不需要等待图片,css文件,或者其他文件加载完毕才执行。可以让用户能够尽早的与用户进行交互。

  1. EventUtil.addHandler(document,'DOMContentLoaded',function(){
  2. alert('我可以先执行,哈哈')
  3. })

事件委托:

每个函数都是对象,都会占用内存,内存中的对象越多,性能就越差。对事件处理程序过多问题的解决方案就是事件委托。

事件委托利用事件冒泡,只指定一个事件处理程序即可,就可以管理某一个类型的所有事件。例如:

有三个li,都需要一个click事件,此时不需要给每个li都绑定click事件,主要给他的父级 ul增加一个绑定事件即可。这样点击li,利用冒泡,直接触发ul的click,只要判断是哪个li的id

点击即可。而不需要三个li都绑定click事件。

  1. <ul id="myLinks">
  2. <li id="myLi1">text1</li>
  3. <li id="myLi2">text2</li>
  4. <li id="myLi3">text3</li>
  5. </ul>

小小总结,有误之处,欢迎指出

深入理解javascript事件流的更多相关文章

  1. 理解DOM事件流的三个阶段

    本文主要解决两个问题: 1.什么是事件流 2.DOM事件流的三个阶段 事件流之事件冒泡与事件捕获 在浏览器发展的过程中,开发团队遇到了一个问题.那就是页面中的哪一部分拥有特定的事件? 可以想象画在一张 ...

  2. JavaScript事件流原理解析

    一.为什么会有这一篇的文章 国庆前几天由于任务比较重,要赶在国庆前把一个进度的任务开发完成,所以也就有点赶,但是却遇到了一个比较奇怪的Bug,导致了任务比预计的延迟了几个小时,对此深表遗憾,所以利用国 ...

  3. 浅析JavaScript事件流——冒泡

    一.什么是事件冒泡流 我们知道事件流指的是从页面中接受事件的顺序. 为了形象理解事件冒泡,可以想象三军主将诸葛亮,在帐内运筹帷幄,眼观六路耳听八方,这时候前方的战事情况就需要靠传令兵来传达,当第一位传 ...

  4. 【原】javascript事件流

    摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊.本文大部分内容参考<javascript高级程序设计第三版> 先来一段书里的原 ...

  5. 深入了解javascript事件流

    摘要:事件流这个东西是比较重要的,为了让自己更加理解js中的事件流,必须整理整理,梳理一下事件流的各种东西啊.本文大部分内容参考<javascript高级程序设计第三版> 先来一段书里的原 ...

  6. 深入理解JavaScript 事件

    本文总结自<JavaScript高级程序设计>以及自己平时的经验,针对较新浏览器以及 DOM3 级事件标准(2016年8月),对少部分内容作了更正,增加了各种例子及解析. 如无特殊说明,本 ...

  7. 从click事件理解DOM事件流

    事件流是用来解释页面上的不同元素接受一个事件的顺序,首先要明确两点: 1.一个事件的影响元素可能不止一个(同心圆理论),但目标元素只有一个. 2.如果这些元素都绑定了相同名称的事件函数,我们怎么知道这 ...

  8. JavaScript事件流

    什么是JS事件流 早期的IE事件传播方向为由上至下,即从document逐级向下传播到目标元素:而Netscape公司的Netscape Navigator则是朝相反的方向传播, 也就是从目标元素开始 ...

  9. javaScript事件流是什么?

    一.事件 事件是文档或者浏览器窗口中发生的,特定的交互瞬间. 事件是用户或浏览器自身执行的某种动作,如click,load和mouseover都是事件的名字. 事件是javaScript和DOM之间交 ...

随机推荐

  1. Android菜鸟成长记4-button点击事件

    Button 1.button按钮的创建 一般来说,在我们新建一个Android项目的时候,会有会默认有一个activity_main.xml的文件 如果你在新建项目的时候,把Create Activ ...

  2. Prefab强制使用文本模式

    [Prefab强制使用文本模式] Edit -> ProjectSetting -> Editor:

  3. 开源PLM软件Aras详解四 ItemType的概念

    首先,我们需要了解什么是ItemType,俗称对象类 官方一点就是ItemType是一个用来定义业务对象类的业务对象类 通过ItemType定义的每个业务对象类可以产生各自的实例对象 通过ItemTy ...

  4. haploview出现"invalid affected status"的解决方法

    haploview弹出这种错误是因为haploview的缺失值默认为0,而plink文件的缺失值一般用"-9"表示,当ped文件的缺失值为"-9"时,haplo ...

  5. 第一章 tomcat安装与启动

    一.安装 1.下载tomcat安装包 2.解压安装包 3.配置环境变量 打开~/.bash_profile文件,输入一下两句话: export TOMCAT_HOME=/Users/enniu1/De ...

  6. Python环境下NIPIR(ICTCLAS2014)中文分词系统使用攻略

    一.安装 官方链接:http://pynlpir.readthedocs.org/en/latest/installation.html 官方网页中介绍了几种安装方法,大家根据个人需要,自行参考!我采 ...

  7. 音痴又音痴的LT (vector)

    http://acm.nyist.net/JudgeOnline/problem.php?pid=1261 分析:若是每次都想用sort继而来查第k个数,那会T的特别惨~ C++内置函数upperbo ...

  8. 柬埔寨手机上网资费套餐(3G/4G上网)

    柬埔寨三大运营商 Cellcard   官网套餐详情http://www.cellcard.com.kh/cellcard-internet Metfone  官网套餐详情http://www.met ...

  9. php数组函数

    1.键值函数 array_values()返回数组元素值,组成一个新的索引数组 2.array_keys()返回数组所有键名,组成一个索引数组 3.in_array()检查数组中是否存在某个值 4.a ...

  10. android压力测试命令monkey详解

    一.Monkey 是什么?Monkey 就是SDK中附带的一个工具. 二.Monkey 测试的目的?:该工具用于进行压力测试. 然后开发人员结合monkey 打印的日志 和系统打印的日志,结局测试中出 ...