带你快速理解javascript中的事件模型


Posted in Javascript onAugust 14, 2017

javascript中有两种事件模型:DOM0,DOM2。而对于这两种的时间模型,我一直不是非常的清楚,现在通过网上查阅资料终于明白了一些。

一.  DOM0级事件模型

DOM0级事件模型是早期的事件模型,所有的浏览器都是支持的,而且其实现也是比较简单。代码如下:

<p id = 'click'>click me</p>
<script>
 document.getElementById('click').onclick = function(event){
  alert(event.target);
 }
</script>

这种事件模型就是直接在dom对象上注册事件名称,这段代码就是在p标签上注册了一个onclick事件,在这个事件函数内部输出点击的目标。而解除事件则更加简单,就是将null复制给事件函数,如下:

document.getElementById('click'_).onclick = null;

由此我们可以知道dom0中,一个dom对象只能注册一个同类型的函数,因为注册多个同类型的函数的话,就会发生覆盖,之前注册的函数就会无效。

var click = document.getElementById('click');
click.onclick = function(){
 alert('you click the first function');
};
click.onclick = function(){
 alert('you click the second function')
}

在这段代码中,我们为dom对象注册了两个onclick函数,但是结果是只执行了第二个注册的函数,前面所注册的函数被覆盖了。

二.   DOM2级事件模型

1.  事件捕获和事件冒泡(capture,bubble)

首先,IE8及以下是不支持这种事件模型的。事件捕获和事件冒泡的机制如下图:

带你快速理解javascript中的事件模型

如上图所示,123代表事件捕获,4567代表事件冒泡。首先我们使用下面的代码:

<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'>
 <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div>
</div>

假设我们点击了ID为inner的div,那么此时的事件流程就是,首先执行捕获阶段:document-html-body-div(outer)。然后执行冒泡阶段:div(inner)-div(outer)-body-html-document。

  2.   DOM2级的注册事件和解除事件

在DOM2级中使用addEventListener和removeEventListener来注册和解除事件(IE8及之前版本不支持)。这种函数较之之前的方法好处是一个dom对象可以注册多个相同类型的事件,不会发生事件的覆盖,会依次的执行各个事件函数。

addEventListener('事件名称','事件回调','捕获/冒泡')。示例如下:

<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'>
 <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div>
</div>
<script>
 var click = document.getElementById('inner');
 click.addEventListener('click',function(){
  alert('click one');
 },false);
 click.addEventListener('click',function(){
  alert('click two');
 },false);
</script>

首先我们要知道addEventListenr的第一个参数是事件名称,与DOM0级不同的是没有”on“,另外第三个参数代表捕获还是冒泡,true代表捕获事件,false代表冒泡事件。

而在这段代码中,我们为inner的div注册了两个click事件函数,结果是浏览器会依次执行这两个函数。

下面我们演示如何使用事件流的发生机制。

<div id = 'outer' style = 'margin: 100px 0 0 100px; width: 200px;height: 200px; background: red;'>
 <div id="inner" style = 'margin-left:20px; width: 50px;height:50px; background: green;'></div>
</div>
<script>
 var click = document.getElementById('inner');
 var clickouter = document.getElementById('outer');
 click.addEventListener('click',function(){
  alert('inner show');
 },true);
 clickouter.addEventListener('click',function(){
  alert('outer show');
 },true);
</script>

这段代码,我们使用了捕获事件,由于inner是嵌套在outer中的,所以我们知道当使用捕获的时候outer是应该首先捕获到这个事件的,其次inner才能捕获到这个事件。那么结果就是outer首先执行,其次是inner执行。

那么我把outer的执行时机改为冒泡的阶段呢?

alickouter.addEventListener('click',function(){
 alert('outer show'); 
},false);

这种情况下,就是先执行inner后执行outer了。同理我们把二者的事件执行时机都改为冒泡阶段的话,依旧是先执行inner后执行outer。那么还有个问题,就是如果我们把inner注册两个click事件,一个是在捕获阶段,另一个是在冒泡阶段,也就是说把addEventListenter的第三个参数分别设置为false和true,那么执行的顺序又是怎样的呢。

<script>
 var click = document.getElementById('inner');
 var clickouter = document.getElementById('outer');
 click.addEventListener('click',function(){
  alert('capture show');
 },true);
 click.addEventListener('click',function(){
  alert('bubble show');
 },false);
</script>

这种情况下首先这些的是capture show,其次是bubble show。但是这种结果是与注册的顺序有关系的,先注册就先执行。因为我们在看事件捕获和事件冒泡示意图,发现最后具体的dom对象是只有一个的。

那么 如果我们给outer和inner都注册了click事件但是我不希望outer执行怎么办呢?这个时候我们就需要用到stopPropagation函数了,这个函数是用来阻止冒泡,言下之意是让事件不再继续冒泡下去,这样接下来注册同样类型事件的dom对象就不会执行了。

比如在自制下拉框的时候,我们点击浏览器的其他位置,我们需要下拉框的options隐藏,这时我们就要用到stopPropagation了。如下:

<script>
 var click = document.getElementById('inner');
 var clickouter = document.getElementById('outer');
 click.addEventListener('click',function(event){
  alert('inner show');
  event.stopPropagation();
 },false);
 clickouter.addEventListener('click',function(){
  alert('outer show');
 },false);
</script>

正常的情况下,我们在不添加stopPropagation函数时,首先应该执行inner,然后执行outer,但是当我们在inner的事件函数中添加了stopPropagation函数之后,执行完inner的事件函数之后,就不会在执行outer的事件函数了,也可以理解为事件冒泡到inner之后就消失了,因此也就不会在执行接下来的事件函数了。

由于事件捕获阶段没有可以阻止事件的函数,所以一般都是设置为事件冒泡。

好了以上就是全部内容啦 ,希望对大家的学习有所帮助~~

Javascript 相关文章推荐
网上抓的一个特效
May 11 Javascript
javascript折半查找详解
Jan 26 Javascript
js代码实现点击按钮出现60秒倒计时
Jan 28 Javascript
jQuery实现的导航下拉菜单效果示例
Sep 05 Javascript
基于JavaScript实现购物网站商品放大镜效果
Sep 06 Javascript
将Sublime Text 3 添加到右键中的简单方法
Dec 12 Javascript
基于webpack.config.js 参数详解
Mar 20 Javascript
记录一篇关于redux-saga的基本使用过程
Aug 18 Javascript
详解适配器在JavaScript中的体现
Sep 28 Javascript
jQuery动态生成的元素绑定事件操作实例分析
May 04 jQuery
JavaScript之数组扁平化详解
Jun 03 Javascript
Vue props中Object和Array设置默认值操作
Jul 30 Javascript
JS获取子、父、兄节点方法小结
Aug 14 #Javascript
JS传播事件、取消事件默认行为、阻止事件传播详解
Aug 14 #Javascript
JS如何实现在页面上快速定位(锚点跳转问题)
Aug 14 #Javascript
JavaScript实现动态添加Form表单元素的方法示例
Aug 14 #Javascript
JavaScript实现的搜索及高亮显示功能示例
Aug 14 #Javascript
带你了解session和cookie作用原理区别和用法
Aug 14 #Javascript
react.js使用webpack搭配环境的入门教程
Aug 14 #Javascript
You might like
PHP 编程请选择正确的文本编辑软件
2006/12/21 PHP
php 3行代码的分页算法(求起始页和结束页)
2009/10/21 PHP
PHP分页初探 一个最简单的PHP分页代码的简单实现
2016/06/21 PHP
php从数据库读取数据,并以json格式返回数据的方法
2018/08/21 PHP
JavaScript中关于indexOf的使用方法与问题小结
2010/08/05 Javascript
js实现图片点击左右轮播
2015/07/08 Javascript
分享纯手写漂亮的表单验证
2015/11/19 Javascript
一篇文章掌握RequireJS常用知识
2016/01/26 Javascript
Bootstrap每天必学之导航条(二)
2016/03/01 Javascript
基于JQuery的购物车添加删除以及结算功能示例
2017/03/08 Javascript
详解angularjs获取元素以及angular.element()用法
2017/07/25 Javascript
详解Angular2学习笔记之Html属性绑定
2018/01/03 Javascript
jquery+css3实现熊猫tv导航代码分享
2018/02/12 jQuery
nodejs高大上的部署方式(PM2)
2018/09/11 NodeJs
谈谈为什么你的 JavaScript 代码如此冗长
2019/01/30 Javascript
Koa 中的错误处理解析
2019/04/09 Javascript
vue实现树形结构样式和功能的实例代码
2019/10/15 Javascript
[07:06]2018DOTA2国际邀请赛寻真——卫冕冠军Team Liquid
2018/08/10 DOTA
Windows下Anaconda和PyCharm的安装与使用详解
2020/04/23 Python
pip已经安装好第三方库但pycharm中import时还是标红的解决方案
2020/10/09 Python
Django model class Meta原理解析
2020/11/14 Python
python给list排序的简单方法
2020/12/10 Python
Python制作简单的剪刀石头布游戏
2020/12/10 Python
python 基于opencv实现图像增强
2020/12/23 Python
基于HTML5+CSS3实现简单的时钟效果
2017/09/11 HTML / CSS
澳大利亚领先的在线美容商城:Adore Beauty
2017/04/14 全球购物
美国在线肉类和海鲜配送:Crowd Cow
2020/10/02 全球购物
关联、聚合(Aggregation)以及组合(Composition)的区别
2012/02/29 面试题
财务信息服务专业自荐书范文
2014/02/08 职场文书
2014机关干部学习“焦裕禄精神”思想汇报
2014/09/19 职场文书
销售经理助理岗位职责
2015/04/13 职场文书
初中生物教学随笔
2015/08/15 职场文书
python中pandas对多列进行分组统计的实现
2021/06/18 Python
SQL实战演练之网上商城数据库商品类别数据操作
2021/10/24 MySQL
忘记Grafana不要紧2种Grafana重置admin密码方法详细步骤
2022/04/07 Servers
前端传参数进行Mybatis调用mysql存储过程执行返回值详解
2022/08/14 MySQL