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() // ...
随机推荐
- nodejs进阶(6)—连接MySQL数据库
1. 建库连库 连接MySQL数据库需要安装支持 npm install mysql 我们需要提前安装按mysql sever端 建一个数据库mydb1 mysql> CREATE DATABA ...
- MySQL高级知识- MySQL的架构介绍
[TOC] 1.MySQL 简介 概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司. MySQL是一种关联数据库管理系统,将数据保存在不同的表中,而 ...
- 一起来玩echarts系列(一)------箱线图的分析与绘制
一.箱线图 Box-plot 箱线图一般被用作显示数据分散情况.具体是计算一组数据的中位数.25%分位数.75%分位数.上边界.下边界,来将数据从大到小排列,直观展示数据整体的分布情况. 大部分正常数 ...
- Javascript - Promise学习笔记
最近工作轻松了点,想起了以前总是看到的一个单词promise,于是耐心下来学习了一下. 一:Promise是什么?为什么会有这个东西? 首先说明,Promise是为了解决javascript异步编 ...
- Linux安装LAMP开发环境及配置文件管理
Linux主要分为两大系发行版,分别是RedHat和Debian,lamp环境的安装和配置也会有所不同,所以分别以CentOS 7.1和Ubuntu 14.04做为主机(L) Linux下安装软件,最 ...
- ExtJS 4.2 Grid组件的单元格合并
ExtJS 4.2 Grid组件本身并没有提供单元格合并功能,需要自己实现这个功能. 目录 1. 原理 2. 多列合并 3. 代码与在线演示 1. 原理 1.1 HTML代码分析 首先创建一个Grid ...
- SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)
前言 本节我们来综合比较NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL的性能,简短的内容,深入的理解,Always to review the basics. ...
- angular2系列教程(六)两种pipe:函数式编程与面向对象编程
今天,我们要讲的是angualr2的pipe这个知识点. 例子
- C#如何在PDF文件添加图片印章
文档中添加印章可以起一定的作用,比如,防止文件随意被使用,或者确保文档内容的安全性和权威性.C#添加图片印章其实也有很多实现方法,这里我使用的是免费的第三方软件Free Spire.PDF,向大家阐述 ...
- GPG终极指南(加密/签名)
我们平时都听过非对称加密,公钥和私钥,签名验证,但这些证书都是怎么得到的呢?本篇文章会解答这些问题. 背景介绍 加密的一个简单但又实用的任务就是发送加密电子邮件.多年来,为电子邮件进行加密的标准一直是 ...