带你快速理解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 相关文章推荐
扩展JS Date对象时间格式化功能的小例子
Dec 02 Javascript
JS+CSS实现可拖拽的漂亮圆角特效弹出层完整实例
Feb 13 Javascript
js实现图片和链接文字同步切换特效的方法
Feb 20 Javascript
分享9个最好用的JavaScript开发工具和代码编辑器
Mar 24 Javascript
信息页文内画中画广告js实现代码(文中加载广告方式)
Jan 03 Javascript
浅析JavaScript作用域链、执行上下文与闭包
Feb 01 Javascript
微信小程序购物商城系统开发系列-工具篇的介绍
Nov 21 Javascript
利用jQuery插件imgAreaSelect实现图片上传裁剪(放大缩小)
Dec 02 Javascript
JavaScript之filter_动力节点Java学院整理
Jun 28 Javascript
详解JS实现系统登录页的登录和验证
Apr 29 Javascript
微信小程序开发实现消息推送
Nov 18 Javascript
vue.js 输入框输入值自动过滤特殊字符替换中问标点操作
Aug 31 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
使用 eAccelerator加速PHP代码的方法
2007/09/30 PHP
CI框架源码阅读,系统常量文件constants.php的配置
2013/02/28 PHP
php进行支付宝开发中return_url和notify_url的区别分析
2014/12/22 PHP
php 开发中加密的几种方法总结
2017/03/22 PHP
PHP基于双向链表与排序操作实现的会员排名功能示例
2017/12/26 PHP
NODE.JS加密模块CRYPTO常用方法介绍
2014/06/05 Javascript
JS实现在页面随时自定义背景颜色的方法
2015/02/27 Javascript
JavaScript原生对象之String对象的属性和方法详解
2015/03/13 Javascript
复杂的javascript窗口分帧解析
2016/02/19 Javascript
jQuery实现手机自定义弹出输入框
2016/06/13 Javascript
JS当前页面登录注册框,固定DIV,底层阴影的实例代码
2016/09/29 Javascript
JavaScript用JSONP跨域请求数据实例详解
2017/01/06 Javascript
jQuery中Chosen三级联动功能实例代码
2017/03/07 Javascript
Vue+webpack+Element 兼容问题总结(小结)
2018/08/16 Javascript
微信小程序实现单选选项卡切换效果
2020/06/19 Javascript
小程序两种滚动公告栏的实现方法
2019/09/17 Javascript
浅析JS中NEW的实现原理及重写
2020/02/20 Javascript
html-webpack-plugin修改页面的title的方法
2020/06/18 Javascript
用python实现面向对像的ASP程序实例
2014/11/10 Python
python3中dict(字典)的使用方法示例
2017/03/22 Python
Pycharm使用之设置代码字体大小和颜色主题的教程
2019/07/12 Python
numpy.array 操作使用简单总结
2019/11/08 Python
Python 中使用 PyMySQL模块操作数据库的方法
2019/11/10 Python
Pytorch1.5.1版本安装的方法步骤
2020/12/31 Python
Genny意大利官网:意大利高级时装品牌
2020/04/15 全球购物
MVC的各个部分都有那些技术来实现?如何实现?
2016/04/21 面试题
幼儿师范毕业生自荐信
2013/11/09 职场文书
《雷鸣电闪波尔卡》教学反思
2014/02/23 职场文书
《大禹治水》教学反思
2014/04/27 职场文书
活动总结结尾怎么写
2014/08/30 职场文书
祖国在我心中演讲稿(小学生)
2014/09/23 职场文书
体检通知范文
2015/04/21 职场文书
2015年药店店长工作总结
2015/04/29 职场文书
销售口号霸气押韵
2015/12/24 职场文书
中国式结婚:司仪主持词(范文)
2019/07/25 职场文书
一文教你快速生成MySQL数据库关系图
2022/06/28 Redis