带你快速理解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 相关文章推荐
十个迅速提升JQuery性能让你的JQuery跑得更快
Dec 10 Javascript
JavaScript表单通过正则表达式验证电话号码
Mar 14 Javascript
浅析Node在构建超媒体API中的作用
Jul 30 Javascript
Node.js中的流(Stream)介绍
Mar 30 Javascript
angularjs学习笔记之三大模块(modal,controller,view)
Sep 26 Javascript
jQuery Validate表单验证插件 添加class属性形式的校验
Jan 18 Javascript
React.js入门学习第一篇
Mar 30 Javascript
JS组件Bootstrap按钮组与下拉按钮详解
May 10 Javascript
vue-cli2打包前和打包后的css前缀不一致的问题解决
Aug 24 Javascript
发布Angular应用至生产环境的方法
Dec 10 Javascript
Vue传参一箩筐(页面、组件)
Apr 04 Javascript
laydate只显示时分 不显示秒的功能实现方法
Sep 28 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快递单号查询接口使用示例
2014/05/05 PHP
PHP的魔术常量__METHOD__简介
2014/07/08 PHP
php实现汉字验证码和算式验证码的方法
2015/03/07 PHP
php parse_str() 函数的定义和用法
2016/05/23 PHP
PHP实现的pdo连接数据库并插入数据功能简单示例
2019/03/30 PHP
根据判断浏览器类型屏幕分辨率自动调用不同CSS的代码
2007/02/22 Javascript
jQuery 选择器理解
2010/03/16 Javascript
jquery 3D球状导航的文章分类
2010/07/06 Javascript
jquery插件制作 手风琴Panel效果实现
2012/08/17 Javascript
几种经典排序算法的JS实现方法
2016/03/25 Javascript
基于RequireJS和JQuery的模块化编程日常问题解析
2016/04/14 Javascript
Knockoutjs 学习系列(一)ko初体验
2016/06/07 Javascript
Javascript中prototype的使用详解
2016/06/18 Javascript
JavaScript 深层克隆对象详解及实例
2016/11/03 Javascript
jQuery插件WebUploader实现文件上传
2016/11/07 Javascript
JS验证字符串功能
2017/02/22 Javascript
vue2.0实现移动端的输入框实时检索更新列表功能
2018/05/08 Javascript
JavaScript实现表单注册、表单验证、运算符功能
2018/10/15 Javascript
python实现颜色rgb和hex相互转换的函数
2015/03/19 Python
python opencv设置摄像头分辨率以及各个参数的方法
2018/04/02 Python
Python中.join()和os.path.join()两个函数的用法详解
2018/06/11 Python
20行python代码实现人脸识别
2019/05/05 Python
python操作kafka实践的示例代码
2019/06/19 Python
python写入数据到csv或xlsx文件的3种方法
2019/08/23 Python
Django 后台带有字典的列表数据与页面js交互实例
2020/04/03 Python
英国最大的电子产品和家电零售企业:Currys PC World
2016/09/24 全球购物
香港现代设计家具品牌:Ziinlife Furniture
2018/11/13 全球购物
薇姿法国官网:Vichy法国
2021/01/28 全球购物
法律七进实施方案
2014/03/15 职场文书
群众路线剖析材料(四风)
2014/11/05 职场文书
军训阅兵新闻稿
2015/07/17 职场文书
2019年冬至:天冷暖人心的问候祝福语大全
2019/12/20 职场文书
nginx对http请求处理的各个阶段详析
2021/03/31 Servers
Spring Boot mybatis-config 和 log4j 输出sql 日志的方式
2021/07/26 Java/Android
《艾尔登法环》1.03.3补丁上线 碎星伤害调整
2022/04/06 其他游戏
深入理解 Golang 的字符串
2022/05/04 Golang