Javascript事件模型系列(二)事件的捕获-冒泡机制及事件委托机制
一、事件的捕获与冒泡
由W3C规定的DOM2标准中,一次事件的完整过程包括三步:捕获→执行目标元素的监听函数→冒泡,在捕获和冒泡阶段,会依次检查途径的每个节点,如果该节点注册了相应的监听函数,则执行监听函数。以下面的HTML结构为例:
<div id="parentdiv">
父亲
<div id="childdiv">孩子</div>
</div>
执行的流程应该是这样的:
下面是一组例子,分别点击孩子节点可以清楚的看到第三个参数的影响:
var parent1 = document.getElementById('parentdiv1');
var child1 = document.getElementById('childdiv1');
parent.addEventListener('click',function(){alert('父亲被点击了');},true);//第三个参数为true
child.addEventListener('click',function(){alert('孩子被点击了');},false);
var parent2 = document.getElementById('parentdiv2');
var child2 = document.getElementById('childdiv2');
parent.addEventListener('click',function(){alert('父亲被点击了');},false);//第三个参数为false
child.addEventListener('click',function(){alert('孩子被点击了');},false);
var parent3 = document.getElementById('parentdiv3');
var child3 = document.getElementById('childdiv3');
parent.addEventListener('click',function(){alert('父亲被点击了');},true);//第三个参数为true
parent.addEventListener('click',function(){alert('父亲被点击了');},false);//第三个参数为false
child.addEventListener('click',function(){alert('孩子被点击了');},false);
如果不想让事件向上冒泡,可以在监听函数中调用event.stopPrapagation()来完成,这样父亲节点就捕捉不到该事件了。在实际的开发中,这一用处还是挺多的。
二、事件委托机制
知道了事件的捕获冒泡机制,我们可以利用它来实现更方便的程序控制,事件委托便是最典型的应用之一。下面来说说javascript中的事件委托机制。什么叫委托呢?想想我们现实生活中,自己不想干的事,让别人来帮忙完成,这就是把事情“委托”给别人。Javascript的事件委托机制也是这个道理,本来一个监听函数要处理节点a触发的事件,现在把这个监听函数绑定到节点a的父层节点上,让它的父辈来完成事件的监听,这样就把事情“委托”了过去。在父辈元素的监听函数中,可通过event.target属性拿到触发事件的原始元素,然后再对其进行相关处理。
那这样做有什么好处呢?最大的用处便是监听动态增加的元素。比如我们现在有这样的需求,点击下面每个列表项弹出各自的内容,现在随着web应用的盛行,网页中使用异步请求来动态加载节点已经变的很普遍,所以我们点击下方的按钮要在列表中增加一项,并且点击新增加的节点也要弹出内容。HTML结构如下:
<ol id="olist">
<li>列表内容1</li>
<li>列表内容2</li>
<li>列表内容3</li>
<li>列表内容4</li>
<li>列表内容5</li>
</ol>
若我们使用之前的监听器绑定方式,需要遍历所有的li元素并监听,代码应该是这样的:
var listArray = document.getElementById('olist').childNodes;
for(var i=0;i<listArray.length;i++){
listArray[i].addEventListener('click',function({
alert(this.innerText);
});
}
运行效果如下:
- 列表内容1
- 列表内容2
- 列表内容3
- 列表内容4
- 列表内容5
可以发现当新增元素后,点击它并没有弹出内容。那是当然的了,因为我们并没有给新增的元素绑定监听器,为了实现点击新增元素也弹出内容,我们不得不在每次新增一个元素后,再进行一次绑定。加一个绑一个,加一个绑一个,累不累啊!你不累浏览器都累了!这样做导致的性能开销是可想而知的,而且浏览器还要维系n多元素与应的监听函数的映射关系,会占用大量内存。
面对这样拖沓冗杂的代码,你是不是已经不能忍,想要高喊一声:大地!快使用光能力量!好,接下来该秘密武器登场了,看看使用事件委托的效果,代码如下:
var olist = document.getElementById('olist');
olist.addEventListener('click',function(){
alert(event.target.innerText);
},false);
看看实际运行的效果:
- 列表内容1
- 列表内容2
- 列表内容3
- 列表内容4
- 列表内容5
我们并未给li元素绑定任何监听器,而是监听它的父元素ul,等到事件冒泡上来的时候,在处理函数中通过event.target获得触发事件的li元素,进行相关处理。这样做的好处是显而易见的,首先只进行了一次监听器的绑定,浏览器轻松,其次动态增加元素后你也不必要再绑定监听器,你也轻松。正所谓大家好才是真的好!
本篇的基本内容就介绍完了,你是不是感觉有点奇妙,我平时写程序的时候没关心这些也仍然能完成工作呀?那我就得问你是不是使用js框架,使用jQuery了,事实上,jQuery提供的on、live等方法就已经对事件委托进行了封装,为委托机制的推广悄悄做了底层贡献,你没感觉到而已。jQuery中的各种事件监听方式也需要我们有一个清楚的了解,才能正确的使用,高效的完成工作。这些内容将放在下一篇介绍。
Javascript事件模型系列(二)事件的捕获-冒泡机制及事件委托机制的更多相关文章
- Javascript事件模型系列(四)我所理解的javascript自定义事件
被我拖延了将近一个月的javascript事件模型系列终于迎来了第四篇,也是我计划中的最后一篇,说来太惭愧了,本来计划一到两个星期写完的,谁知中间遇到了很多事情,公司的个人的,搞的自己心烦意乱浮躁了一 ...
- Javascript事件模型系列(一)事件及事件的三种模型
一.开篇 在学习javascript之初,就在网上看过不少介绍javascript事件的文章,毕竟是js基础中的基础,文章零零散散有不少,但遗憾的是没有看到比较全面的系列文章.犹记得去年这个时候,参加 ...
- Javascript事件模型系列(三)jQuery中的事件监听方式及异同点
作为全球最知名的js框架之一,jQuery的火热程度堪称无与伦比,简单易学的API再加丰富的插件,几乎是每个前端程序员的必修课.从读<锋利的jQuery>开始,到现在使用jQuery有一年 ...
- information_schema系列二(列,列权限,事件,存储引擎)
这个系列的文章主要是为了能够让自己了解MySQL5.7的一些系统表,统一做一下备注和使用,也希望分享出来让大家能够有一点点的受益. 1:COLUMNS 老规矩.查一下这个表,看一下记录,由于这个是看表 ...
- Javascript事件模型(二):Javascript事件的父元素和子元素
DOM事件标准定义了两种事件流,分别是捕获和冒泡.默认情况下,事件使用冒泡事件流,不使用捕获事件流.你可以指定使用捕获事件流,方法是在注册事件时传入useCapture参数,将这个参数设为true. ...
- ECharts 报表事件联动系列二:柱状图,饼状图添加事件
代码如下: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" c ...
- JQuery日记6.7 Javascript异步模型(二)
异步模型看起来非常美,但事实上它也是有天生缺陷的.看以下代码 try { setTimeout( function(){ throw new Error( '你抓不到我的!' ); }, 100); ...
- javascript类继承系列二(原型链)
原型链是采用最主要的继承方式,原理:每一个类(构造器,js中的function)都有一个原型属性(prototype)指向一个原型对象,原型对象有一个构造器(constructor),它又指回到fun ...
- 轻松学习JavaScript二十七:DOM编程学习之事件模型
在介绍事件模型之前,我们先来看什么是事件和什么是event对象. 一事件介绍 JavaScript事件是由訪问Web页面的用户引起的一系列操作,使我们有能力创建动态页面.事件是能够被 JavaScri ...
随机推荐
- [Docker]Docker快速上手学习笔记
0. 学习的一些疑问 如何热更新镜像(images)?(你可以快速启动或者销毁容器.这种时间几乎是实时的) 如何热更新游戏服? 好处在于各个应用之间环境相互独立,即使某一个容器崩溃也不会影响到其它容器 ...
- JQuery初体验
虽然做b/s也有一年半了,但是还没怎么认真的去看JQuery,趁自己生病的这几天,恶补一下JQuery方面的知识,保持学习的态度,内容很简单,聊以自慰一下>_<.废话不多说,直接上代码了. ...
- Ajax Step By Step3
第三[.$.getScript()和$.getJSON()] jQuery 提供了一组用于特定异步加载的方法:$.getScript(),用于加载特定的 JS 文件: $.getJSON(),用于专门 ...
- (Python)继承
面向对象的另一个特性是继承,继承可以更好的代码重用. 例如一个学校里面的成员有老师.学生.老师和学生都有共同的属性名字和年纪.但老师还有它自己的属性,如工资.学生也有它的属性,如成绩. 因此我们可以设 ...
- 高尔夫管理系统SSH
登录-----------http://localhost:8080/GOLF/Denglu 一.Action 1.处理今日消费数据逻辑的 package com.chinasofti.golf.ac ...
- html5 上传头像的裁剪
本示例使用HTML5 canvas,简单的编写了上传头像的裁剪效果,移动端支持拖拽后裁剪, 虽然样式不好看,但是功能还算全: 下图为裁剪后的效果: html部分: <!DOCTYPE html& ...
- 关于.NET大数据量大并发量的数据连接池管理
转自:http://www.cnblogs.com/virusswb/archive/2010/01/08/1642055.html 我以前对.NET连接池的认识是错误的,原来以为在web.confi ...
- 使用Safari远程调试iOS设备网页
最近在做HTML 5游戏时,发布到手机上访问网页总是莫名其妙出现问题,苦于没有remote debug功能一直没有查找到问题. 这边博客详细介绍了iOS, Android, Windows Phone ...
- 两种状态显示处理. enum , Linq AsEnumerable
1.ENUM protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { GridViewRow ro ...
- vi/vim使用进阶: vimrc初步
本节所用命令的帮助入口: :help compatible :help mapleader :help map :help autocmd 当vim在启动时,如果没有找到vimrc或gvimrc,它缺 ...