本篇主要介绍HTML DOM中的事件流和事件委托。

其他事件文章

1. HTML 事件(一) 事件的介绍

2. HTML 事件(二) 事件的注册与注销

3. HTML 事件(三) 事件流与事件委托

4. 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);
});

  

End
菜单加载中...

HTML 事件(三) 事件流与事件委托的更多相关文章

  1. WPF路由事件三:自定义路由事件

    与依赖项属性类似,WPF也为路由事件提供了WPF事件系统这一组成.为一个类型添加一个路由事件的方式与为类型添加依赖项属性的方法类似,添加一个自定义路由事件的步骤: 一.声明路由事件变量并注册:定义只读 ...

  2. python全栈开发day49-jquery的位置信息、事件流、事件对象,事件委托,事件绑定和解绑

    一.昨日内容回顾    1. jQuery的属性操作 1) html属性操作:attr 2) DOM属性操作:prop 3) 类样式操作:addClass.removeClass.toggleClas ...

  3. JS事件流、事件监听、事件对象、事件委托

    JS事件流: 01.DOM级别和DOM事件 02.JS事件流:页面中接收事件的顺序 事件冒泡阶段-->处于目标阶段-->事件捕获阶段 (事件捕获总发生在事件冒泡前面) 03.捕获:从外向里 ...

  4. [已转移]js事件流之事件冒泡的应用----事件委托

    该文章已转移到博客:https://cynthia0329.github.io/ 什么是事件委托? 它还有一个名字叫事件代理. JavaScript高级程序设计上讲: 事件委托就是利用事件冒泡,只指定 ...

  5. js:事件(注册、解绑、DOM事件流、事件对象、事件委托)

    1.注册事件 (1)传统方式注册事件 <body> <button id="b1">请点击</button> <script> va ...

  6. js--事件流、事件委托、事件阶段

    前言 JavaScript 与 HTML 的交互是通过事件实现的,事件代表文档或浏览器窗口中某个有意义的时刻.可以使用仅在事件发生时执行的监听器(也叫处理程序)订阅事件.本文总结一下 JS 中的事件相 ...

  7. JavaScript事件详解-jQuery的事件实现(三)

    正文 本文所涉及到的jQuery版本是3.1.1,可以在压缩包中找到event模块.该篇算是阅读笔记,jQuery代码太长.... Dean Edward的addEvent.js 相对于zepto的e ...

  8. JS 事件冒泡整理 浏览器的事件流

    JavaScript与HTML的交互通过事件来实现.而浏览器的事件流是一个非常重要的概念.不去讨论那些古老的浏览器有事件捕获与事件冒泡的争议, 只需要知道在DOM2中规定的事件流包括了三个部分,事件捕 ...

  9. jQuery基础(4)- 位置信息、事件流、事件对象、事件代理、jquery事件

    一.jQuery的位置信息 jQuery的位置信是JS的client系列.offset系列.scroll系列封装好的一些简便api. 1.宽度和高度 a.获取宽度和高度,例如: .width() // ...

随机推荐

  1. sublime常用快捷键

    自己觉得比较实用的sublime快捷键: Ctrl + /  ---------------------注释 Ctrl + 滚动 --------------字体变大/缩小 Ctrl + N----- ...

  2. CSS3 3D立方体效果-transform也不过如此

    CSS3系列已经学习了一段时间了,第一篇文章写了一些css3的奇技淫巧,原文戳这里,还获得了较多网友的支持,在此谢过各位,你们的支持是我写文章最大的动力^_^. 那么这一篇文章呢,主要是通过一个3D立 ...

  3. $.extend()的实现源码 --(源码学习1)

    目标: $.extend({         add:function(a,b){             return a + b;         }     }) console.log($.a ...

  4. 启用 Open vSwitch - 每天5分钟玩转 OpenStack(127)

    Linux Bridge 和 Open vSwitch 是目前 OpenStack 中使用最广泛的两种虚机交换机技术. 前面各章节我们已经学习了如何用 Linux Bridge 作为 ML2 mech ...

  5. 展望未来:使用 PostCSS 和 cssnext 书写 CSS

    原文链接:A look into writing future CSS with PostCSS and cssnext 译者:nzbin 像twitter,google,bbc使用的一样,我打算看一 ...

  6. C#多线程之线程同步篇3

    在上一篇C#多线程之线程同步篇2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier ...

  7. 【知识必备】RxJava+Retrofit二次封装最佳结合体验,打造懒人封装框架~

    一.写在前面 相信各位看官对retrofit和rxjava已经耳熟能详了,最近一直在学习retrofit+rxjava的各种封装姿势,也结合自己的理解,一步一步的做起来. 骚年,如果你还没有掌握ret ...

  8. iOS有关横向TableView的东西

    之前看到Apple store里面有横向的tableview,当然也有可能是collectionview啦. 尤其是项目中只有一条那么需要横向滑动的东西,就没有必要使用庞大的collectionvie ...

  9. BPM配置故事之案例6-条件可见与条件必填

    小明兴奋的告诉大毛自己独立解决了必填和水印问题,腹黑的大毛决定给小明出一个进阶问题刷一下存在感. 大毛:我再考考你,我把表单改成了这样(下图).怎么做到,预算状态为"预算内"时,不 ...

  10. SNMP简单网络管理协议

    声明:以下内容是学习谌玺老师视频整理出来(http://edu.51cto.com/course/course_id-861.html) SNMP(Simple Network Management ...