HTML 事件(三) 事件流与事件委托
本篇主要介绍HTML DOM中的事件流和事件委托。
其他事件文章
3. HTML 事件(三) 事件流与事件委托
目录
1. 事件流
1.1 何为事件流
1.2 事件流的三个阶段
1.3 addEventListener()注册事件流的阶段
1.4 阻止事件流的传播
2. 事件委托
2.1 何为事件委托
2.2 ul、li场景示例
2.3 JQuery的事件委托
2.3.1 delegate()
2.3.2 on()
1. 事件流 (Event Flow)
1.1 何为事件流
简单来说HTML的元素会出现嵌套的关系,比如:一个Div嵌套了一个Button按钮,当2个元素都注册了click点击事件。点击里面的Button按钮时,Div的click事件也会触发。
那么问题来了,既然都会触发,得有个触发的顺序吧?是按照Div → Button这样的顺序触发,还是按照Button → Div的顺序触发?
在之前,两大浏览器厂商网景和微软都有各自的触发顺序:
网景的浏览器采用捕获方式:按照Div → Button这样的顺序触发.
而微软的浏览器采用冒泡方式:按照Button → Div的顺序触发。
在2级DOM事件规范制定时干脆合二为一:事件流同时包含了这2个阶段。
1.2 事件流的三个阶段
1.2.1 三个阶段
2级DOM事件规范制定了事件流的三个阶段:捕获阶段、目标阶段和冒泡阶段:
捕获阶段(Capture Phase):事件从最外层的window对象到目标节点的父节点依次触发的阶段。(从外到内)
目标阶段(Target Phase):事件在目标节点上触发时的阶段。
冒泡阶段(Bubbing Phase):事件从目标节点的父节点到最外层的window对象依次触发的阶段。(从内到外)
1.2.2 示例图

1.3 addEventListener()注册事件流的阶段
元素对象通过addEventListener()注册事件时,此方法的的第三个参数可设置本次注册是捕获阶段还是冒泡阶段。
1.3.1 addEventListener()方法说明
语法:EventTarget.addEventListener(eventName, eventHandler [, useCapture] )
参数:
①eventName {string} :所要注册的事件名称,不区分大小写。此名称不需要像注册事件属性那样在前缀加上"on"。如注册鼠标点击事件,写为click。
②eventHandler {function | function Object} :函数或者函数对象。事件触发时所需要执行的函数;当使用函数对象多次注册同一事件时,只当注册一遍。
③useCapture {boolean} 可选 :是否处于捕获阶段,默认为false。
|-true:当前注册的事件为捕获阶段。
|-false:当前注册的事件不为捕获阶段,为冒泡阶段。
1.3.2 示例
示例使用到Event事件对象的部分属性:
readonly Object currentTarget :只读,获取正在处理此事件的对象。
readonly int eventPhase :只读,表示事件的处理阶段:0表示没有正在处理,1表示捕获阶段,2表示目标阶段,3表示冒泡阶段。
readonly Object target :只读,获取触发此事件的对象。
function clickHandle(e){
console.log("事件阶段:"+e.eventPhase+';target:'+e.target+';currentTarget:'+e.currentTarget)
}
window.addEventListener('click',clickHandle,false);
window.addEventListener('click',clickHandle,true);
document.addEventListener('click',clickHandle,false);
document.addEventListener('click',clickHandle,true);
document.documentElement.addEventListener('click',clickHandle,false);
document.documentElement.addEventListener('click',clickHandle,true);
document.body.addEventListener('click',clickHandle,false);
document.body.addEventListener('click',clickHandle,true);
document.getElementById('div').addEventListener('click',clickHandle,false);
document.getElementById('div').addEventListener('click',clickHandle,true);
document.getElementById('btn').addEventListener('click',clickHandle,false);
document.getElementById('btn').addEventListener('click',clickHandle,true);

1.4 阻止事件流的传播
Event 事件对象的stopPropagation()、stopImmediatePropagation()方法可阻止事件流的后续传播。
注:stopImmediatePropagation()方法除了阻止事件流传播还会阻止当前事件在此元素的后续事件处理程序。
事件流的三个阶段调用这2个方法,会有不同的阻止传播方式:
1.4.1 在捕获阶段调用
说明:在捕获阶段调用stopPropagation()方法时,此元素后续的事件流都会阻止,包括捕获阶段、目标阶段、冒泡阶段。
示例:在1.3.2示例代码中的body元素捕获阶段调用此方法
document.body.addEventListener('click',function(e){
console.log("事件阶段:"+e.eventPhase+';target:'+e.target+';currentTarget:'+e.currentTarget)
e.stopPropagation();
},true);
结果:事件流在body的捕获阶段就截至了,后续的阶段都没有执行

1.4.2 在目标阶段调用
说明:在目标段调用stopPropagation()方法时,捕获阶段和目标阶段会执行完毕,冒泡阶段不会被执行。
示例:在1.3.2示例代码中的button按钮元素目标阶段调用此方法
document.getElementById('btn').addEventListener('click',function(e){
console.log("捕获阶段注册:事件阶段:"+e.eventPhase+';target:'+e.target+';currentTarget:'+e.currentTarget)
e.stopPropagation();
},false);
document.getElementById('btn').addEventListener('click',function(e){
console.log("冒泡阶段注册:事件阶段:"+e.eventPhase+';target:'+e.target+';currentTarget:'+e.currentTarget)
e.stopPropagation();
},true);
结果:捕获阶段和目标阶段执行完毕,冒泡阶段未被执行。

1.4.3 在冒泡阶段调用
说明:在冒泡段调用stopPropagation()方法时,捕获阶段和目标阶段会执行完毕,元素后续的冒泡阶段不会被执行。
示例:在1.3.2示例代码中的body冒泡阶段调用此方法
document.body.addEventListener('click',function(e){
console.log("事件阶段:"+e.eventPhase+';target:'+e.target+';currentTarget:'+e.currentTarget)
e.stopPropagation();
},false);
结果:捕获阶段和目标阶段执行完毕,body后续的冒泡阶段未被执行

2. 事件委托(Event Delegate)
2.1 何为事件委托
HTML元素含有嵌套关系,并且事件流含有冒泡阶段。子元素的触发事件会冒泡到父元素的相同事件上。
一般情况只需给子元素注册特定的事件处理程序即可,但当子元素过多或频繁的进行增减操作怎么办?
比如一个ul包含了几十个li元素,对每个li元素进行单独的事件注册会影响性能。而现只要在父元素注册事件监听器,等待li事件触发后的冒泡阶段即可。
简单来说事件委托就是父元素监听子元素的冒泡事件。
2.2 ul、li场景示例
Div容器包含了多个li子元素,在Div容器注册事件委托。
HTML代码:
<div id="div">
<ul id="ul" >
<li data-key="北京">北京</li>
<li data-key="上海">上海</li>
<li data-key="杭州">杭州</li>
</ul>
</div>
JS代码:
document.getElementById('div').addEventListener('click',function(e){
var value=e.target.attributes['data-key'].value; // 获取目标阶段元素的'data-key'属性的值
console.log(value);
});
2.3 JQuery的事件委托
在JQuery中,父元素可调用delegate()、on()作为事件委托使用。
2.3.1 delegate()
语法:$('父元素').delegate( selector [, eventType] [, eventData], handler )
参数:
①selector {string} :子元素的选择器、
②eventType {eventType} 可选 :触发的事件类型。如:click。
③eventData {object} 可选 :触发事件时event.data指向的值。
④handler {function} :事件注册的处理程序。
示例:
$('#div').delegate('li', 'click', function() {
var v = $(this).data('key');
console.log(v);
});
2.3.2 on()
说明:JQuery1.7版本开始时,推荐on()代替delegate()方法。
语法:$('元素').on( events [, selector ] [, data ], handler )
参数:
①events {string} :一个或多个事件名称。
②selector {string} 可选 :子元素选择器。若无此值,表示元素注册本身的事件。若含有此值,表示只有子元素的事件触发,才会触发注册的事件。
③data {object} 可选 :触发事件时的event.data指向的值。
④handler {function} :事件注册的处理程序。
示例:
$('#div').on('click','li',function(e) {
var v = $(this).data('key');
console.log(v);
});
HTML 事件(三) 事件流与事件委托的更多相关文章
- WPF路由事件三:自定义路由事件
与依赖项属性类似,WPF也为路由事件提供了WPF事件系统这一组成.为一个类型添加一个路由事件的方式与为类型添加依赖项属性的方法类似,添加一个自定义路由事件的步骤: 一.声明路由事件变量并注册:定义只读 ...
- python全栈开发day49-jquery的位置信息、事件流、事件对象,事件委托,事件绑定和解绑
一.昨日内容回顾 1. jQuery的属性操作 1) html属性操作:attr 2) DOM属性操作:prop 3) 类样式操作:addClass.removeClass.toggleClas ...
- JS事件流、事件监听、事件对象、事件委托
JS事件流: 01.DOM级别和DOM事件 02.JS事件流:页面中接收事件的顺序 事件冒泡阶段-->处于目标阶段-->事件捕获阶段 (事件捕获总发生在事件冒泡前面) 03.捕获:从外向里 ...
- [已转移]js事件流之事件冒泡的应用----事件委托
该文章已转移到博客:https://cynthia0329.github.io/ 什么是事件委托? 它还有一个名字叫事件代理. JavaScript高级程序设计上讲: 事件委托就是利用事件冒泡,只指定 ...
- js:事件(注册、解绑、DOM事件流、事件对象、事件委托)
1.注册事件 (1)传统方式注册事件 <body> <button id="b1">请点击</button> <script> va ...
- js--事件流、事件委托、事件阶段
前言 JavaScript 与 HTML 的交互是通过事件实现的,事件代表文档或浏览器窗口中某个有意义的时刻.可以使用仅在事件发生时执行的监听器(也叫处理程序)订阅事件.本文总结一下 JS 中的事件相 ...
- JavaScript事件详解-jQuery的事件实现(三)
正文 本文所涉及到的jQuery版本是3.1.1,可以在压缩包中找到event模块.该篇算是阅读笔记,jQuery代码太长.... Dean Edward的addEvent.js 相对于zepto的e ...
- JS 事件冒泡整理 浏览器的事件流
JavaScript与HTML的交互通过事件来实现.而浏览器的事件流是一个非常重要的概念.不去讨论那些古老的浏览器有事件捕获与事件冒泡的争议, 只需要知道在DOM2中规定的事件流包括了三个部分,事件捕 ...
- jQuery基础(4)- 位置信息、事件流、事件对象、事件代理、jquery事件
一.jQuery的位置信息 jQuery的位置信是JS的client系列.offset系列.scroll系列封装好的一些简便api. 1.宽度和高度 a.获取宽度和高度,例如: .width() // ...
随机推荐
- SignalR系列续集[系列8:SignalR的性能监测与服务器的负载测试]
目录 SignalR系列目录 前言 也是好久没写博客了,近期确实很忙,嗯..几个项目..头要炸..今天忙里偷闲.继续我们的小系列.. 先谢谢大家的支持.. 我们来聊聊SignalR的性能监测与服务器的 ...
- 【趣事】用 JavaScript 对抗 DDOS 攻击 (下)
上一篇:http://www.cnblogs.com/index-html/p/js-network-firewall.html 对抗 v2 之前的那些奇技淫巧,纯属娱乐而已,并不能撑多久. 但简单. ...
- Java基础Map接口+Collections
1.Map中我们主要讲两个接口 HashMap 与 LinkedHashMap (1)其中LinkedHashMap是有序的 怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...
- AES加密
package com.edu.hpu; import java.math.BigInteger; import java.security.MessageDigest; import java.se ...
- Android权限管理之RxPermission解决Android 6.0 适配问题
前言: 上篇重点学习了Android 6.0的运行时权限,今天还是围绕着Android 6.0权限适配来总结学习,这里主要介绍一下我们公司解决Android 6.0权限适配的方案:RxJava+RxP ...
- 当web.config文件放置在共享目录下(UNC),启动IIS会提示有错误信息500.19,伴随有错误代码0x80070003和错误代码0x80070005的解决办法
最近遇到一个很有意思的使用环境,操作人员将所有的网站应用内容投放到共享存储里面,并且使用微软的SMB协议将其以CIFS的方式共享出来,使用Windows Server 2008 R2的IIS将其连接起 ...
- 【NLP】蓦然回首:谈谈学习模型的评估系列文章(一)
统计角度窥视模型概念 作者:白宁超 2016年7月18日17:18:43 摘要:写本文的初衷源于基于HMM模型序列标注的一个实验,实验完成之后,迫切想知道采用的序列标注模型的好坏,有哪些指标可以度量. ...
- android studio你可能忽视的细节——启动白屏?drawable和mipmap出现的意义?这里都有!!!
android studio用了很久了,也不知道各位小伙伴有没有还在用eclipse的,如果还有,楼主真心推荐转到android studio来吧,毕竟亲儿子,你会知道除了启动速度稍微慢些,你找不到一 ...
- Win10提示没有权限使用网络资源问题解决
借鉴链接:http://www.cr173.com/html/67361_1.html Win10提示没有权限使用网络资源解决方法 1.打开控制面板; 2.在所有控制面板项中找到凭据管理器; 3.添加 ...
- 《Note --- Unreal 4 --- Sample analyze --- StrategyGame(continue...)》
---------------------------------------------------------------------------------------------------- ...