移除元素所有事件监听_DOM 事件模型或 DOM 事件机制

DOM 事件模型

DOM 的事件操作(监听和触发),都定义在EventTarget接口。所有节点对象都部署了这个接口,其他一些需要事件通信的浏览器内置对象(比如,XMLHttpRequest、AudioNode、AudioContext)也部署了这个接口。

该接口主要提供三个实例方法。

  • addEventListener:绑定事件的监听函数
  • removeEventListener:移除事件的监听函数
  • dispatchEvent:触发事件

事件模型

一个事件发生后,会在子元素及父元素之间进行传播(propagation),这种传播分为三个阶段。

(这种三阶段的传播模型,使得同一个事件会在多个节点上触发。)

    1. 由外向内找监听函数就是事件捕获
    2. 在目标节点触发事件
    3. 由内而外找监听函数就是事件冒泡

通俗一点来说就是一个事件被触发时,浏览器会自动从用户操作标签外的最上级标签逐渐向里检查是否有相同事件,如果有则触发,如果没有则继续向下检查知道用户操作的标签,这过程称为捕获,此时浏览器会继续由用户操作标签继续向是上级标签检查,如果有相同事件则触发,如果没有则继续向上检查直到最上级元素为止,此过程称为冒泡。(有监听函数就执行,并提供事件信息,没有就跳过)

事件传播的最上层对象是window,上例的事件传播顺序,在捕获阶段依次为window、document、html、body、父节点、目标节点,在冒泡阶段依次为目标节点、父节点、body、html、document、window。

DOM事件传播的三个阶段:捕获阶段,目标阶段,冒泡阶段

点击事件

代码:

<div class="grandfather"><div class="father"><div class="son"></div>word</div>
</div>

即.grandfather>.father>.son

给三个div分别添加事件的监听fnYe/fnBa/fnEr

提问1:点击了谁?

点击文字,算不算点击儿子?

点击文字,算不算点击爸爸?

点击文字,算不算点击爷爷?

答案:都算

提问2:调用循序

点击文字,最先调用fnYe/fnBa/fnEr中的那一个函数?

答案:都行

IE5认为先调用fnEr,网景认为先调用fnYe,最后遇到了W3C

2002年,w3c发布标准
文档名为DOM Level 2 Events Specification
规定浏览器应该同时支持两种调用顺序
首先按照grandfather->father->son
然后按照son->father->grandfather

术语:

从外向内找监听函数,叫做事件捕捉
从内向外找监听函数,叫做事件冒泡
那岂不是fnYe/fnBa/fnEr都调用两次,非也!
开发者可以自己决定把fnYe放在捕捉阶段还是放在冒泡阶段

5f4c06474c3e36a92c2f2c78556b3f64.png

addEventListener事件绑定API

IE5*:baba.attachEvent('onclick',fn)//冒泡

网景:baba.addEventListener('click',fn)//捕获

W3C:baba.addEventListener('click',fn,bool)

如果bool不传或为falsy

就让fn走冒泡,即当浏览器在冒泡阶段发现baba有fn监听函数,就会调用fn,并提供时间信息。

如果bool为true

就让fn走捕获,即当浏览器在捕获阶段发现baba有fn监听函数,就会调用fn,并且提供事件信息。

c2116c00ae986bafbd441af619a3749e.png

代码演示:

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>JS Bin</title>
</head>
<body>
<div class="level1 x"><div class="level2 x"><div class="level3 x"><div class="level4 x"><div class="level5 x"><div class="level6 x"><div class="level7 x"></div></div></div></div></div></div>
</div></body>
</html>

CSS:

* {box-sizing: border-box;
}
div[class^=level] {border: 1px solid;border-radius: 50%;display: inline-flex;
}
.level1 {padding: 10px;background: purple;
}
.level2 {padding: 10px;background: blue;
}
.level3 {padding: 10px;background: cyan;
}
.level4 {padding: 10px;background: green;
}
.level5 {padding: 10px;background: yellow;
}
.level6 {padding: 10px;background: orange;
}
.level7 {width: 50px;height: 50px;border: 1px solid;background: red;border-radius: 50%;
}
.x{background: transparent;//把元素的变为透明
}

Javascript代码:

const level1 = document.querySelector('.level1')
const level2 = document.querySelector('.level2')
const level3 = document.querySelector('.level3')
const level4 = document.querySelector('.level4')
const level5 = document.querySelector('.level5')
const level6 = document.querySelector('.level6')
const level7 = document.querySelector('.level7')let n = 1level1.addEventListener('click', (e)=>{const t = e.currentTarget//e只有在点击得一瞬间才会出现,所以要用t来记录一下。setTimeout(()=>{  t.classList.remove('x')},n*1000)n+=1//因为如果每个时间都为1000那么就相当于在8点同时设置很多的闹钟,。知识
})
level2.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{  t.classList.remove('x')},n*1000)n+=1
})
level3.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{  t.classList.remove('x')},n*1000)n+=1
})
level4.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{  t.classList.remove('x')},n*1000)n+=1
})
level5.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{  t.classList.remove('x')},n*1000)n+=1
})
level6.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{  t.classList.remove('x')},n*1000)n+=1
})
level7.addEventListener('click', (e)=>{const t = e.currentTargetsetTimeout(()=>{  t.classList.remove('x')},n*1000)n+=1
})

简化:

const level1 = document.querySelector('.level1')
const level2 = document.querySelector('.level2')
const level3 = document.querySelector('.level3')
const level4 = document.querySelector('.level4')
const level5 = document.querySelector('.level5')
const level6 = document.querySelector('.level6')
const level7 = document.querySelector('.level7')let n = 1const fm = (e)=>{const t = e.currentTargetsetTimeout(()=>{  t.classList.remove('x')},n*1000)n+=1
}const fa = (e)=>{const t =e.currentTargetsetTimeout(()=>{t.classList.add('x')},n*1000)n+=1}level1.addEventListener('click',fm,true)
level1.addEventListener('click',fa)
level2.addEventListener('click',fm,true)
level2.addEventListener('click',fa)
level3.addEventListener('click',fm,true)
level3.addEventListener('click',fa)
level4.addEventListener('click',fm,true)
level4.addEventListener('click',fa)
level5.addEventListener('click',fm,true)
level5.addEventListener('click',fa)
level6.addEventListener('click',fm,true)
level6.addEventListener('click',fa)
level7.addEventListener('click',fm,true)
level7.addEventListener('click',fa)

知识复习:

classList:

定义和用法

classList 属性返回元素的类名,作为 DOMTokenList 对象。

该属性用于在元素中添加,移除及切换 CSS 类。

classList 属性是只读的,但你可以使用 add() 和 remove() 方法修改它。

HTML DOM classList 属性​www.runoob.com

currentTarget 事件属性

定义和用法

currentTarget 事件属性返回其监听器触发事件的节点,即当前处理该事件的元素、文档或窗口。
在捕获和起泡阶段,该属性是非常有用的,因为在这两个节点,它不同于 target 属性。

currentTarget ʼþÊôÐÔ​www.w3school.com.cn

总结:

两个疑问:

儿子被点击,算不算点击老子?

那么先调用老子得函数还是先调用儿子的函数?

捕获冒泡

捕获说先调用爸爸的监听函数

冒泡说先调用儿子的监听函数

W3C时间模型

先捕获(先爸爸=>儿子)再冒泡(再儿子=>爸爸)

注意e对象被传给所有的监听函数

事件结束后,e对象就不存在了

target v.s. currentTarget的区别

区别:

e.target - 用户操作的元素
e.currentTarget-程序员监听的元素
this是e.currentTarget,我个人不推荐使用它

举例:

div>span{文字},用户点击文字
e.target就是span
e.currentTarget就是div

一个特例

背景:

只有一个div被监听(不考虑父子同时被监听)

fn分别再捕获阶段和冒泡阶段监听click事件

用户点击的元素就是开发者监听的

代码:

div.addEventListenter('click',f1)

div.addEventListenter('click',f2,true)

请问,f1先执行还是f2先执行?

如果把两个调换位置?

总结:谁先监听谁先执行。

level7.addEventListener('click',()=>{console.log(2)
},true)//捕获
level7.addEventListener('click',()=>{console.log(1)
})//冒泡

e.stopPropagation():取消冒泡

e.stopPropagation()可打断冒泡,浏览器不再向上走

一般用于封装某些独立组件

注意:捕获不可以取消但是冒泡可以

不可以取消冒泡

有些事件不可以取消冒泡

可以查阅MDN英文版冒泡

比如scroll:

a3f78b9f7ecaf71eeb642ddbc658611b.png

Bubbles:冒泡

Cancelable:是否取消冒泡

如何禁用滚动

取消特定元素的wheel和touchstart的默认动作

JS Bin​js.jirengu.com
458783ef3f4c9d676cfebe3ab8409077.png

浏览器自带事件

来自MDN:

事件参考​developer.mozilla.org
04a10667cec1221014320944799dba8f.png

自定义事件:代码

JS Bin​js.jirengu.com
458783ef3f4c9d676cfebe3ab8409077.png

5a6336f11d64a8a22e2a2916176537a2.png

事件委托:

我委托一个元素帮我监听我本该监听的东西,比如onclick

场景1:

要给100个按钮添加点击事件,咋办?

答:监听这个100个按钮的祖先,等冒泡的时候判断target是不是这100个按钮中的一个

代码:

JS Bin​js.jirengu.com
458783ef3f4c9d676cfebe3ab8409077.png

场景2:

你要监听目前不存在的元素的点击事件?

答:监听祖先,等点击的时候看看是不是监听的元素即可。

优点:省监听数(内存),可以动态监听元素

代码:

JS Bin​js.jirengu.com
458783ef3f4c9d676cfebe3ab8409077.png

封装一个事件委托

只要实行一个函数就可以实现事件委托

要求:

写出这样一个函数on('click','#testDiv','li',fn)

当用户点击#testDiv里面的li元素时,调用fn函数

要求用到事件委托

答案1:判断target是否匹配'li'

答案2:target/target的爸爸/target的爷爷

代码:

JS Bin​js.jirengu.com
458783ef3f4c9d676cfebe3ab8409077.png

错的但是面试可以用:

答:给一个元素加一个监听,看当前的target是否满足监听函数(函数2)中函数2的条件如果满足调用,不满足放过。但是是错的!

代码:

setTimeout(()=>{const button = document.createElement('button')const span = document.createElement('span')span.textContent='click 1'button.appendChild(span)div1.appendChild(button)
},1000)on('click','#div1','button',()=>{//'#div'是选择器不是元素console.log('button 被点击啦')
})
function on(eventType,element,selector,fn){if(!(element instanceof Element)){element = document.querySelector(element)}element.addEventListener(eventType,(e)=>{const t= e.target//被点击的元素是span不是button啦if(t.matches(selector)){//matches用来判断一个元素是否匹配一个选择器,selector是不是一个选择器
span不匹配buttonfn(e)}
})
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/541565.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gettimezone_Java日历getTimeZone()方法与示例

gettimezone日历类的getTimeZone()方法 (Calendar Class getTimeZone() method) getTimeZone() method is available in java.util package. getTimeZone()方法在java.util包中可用。 getTimeZone() method is used to return this Calendar time zone. getTimeZone()方法用于返…

cass展点不在原位置_cass展点之步骤及方法

cass展点之步骤及方法cass展点是根据手工或坐标正反算软件自动计算的结果&#xff0c;利用cass软件将点号、坐标及其高程自动展示到图纸上的一种方法。其基本步骤和方法如下&#xff1a;一、将井下测点的点号、以及计算好的Y坐标、X坐标、及高程由sheet1复制并粘贴到sheet2上面…

Java BufferedWriter close()方法与示例

BufferedWriter类close()方法 (BufferedWriter Class close() method) close() method is available in java.io package. close()方法在java.io包中可用。 close() method is used to flushes the characters from the stream and later will close it by using close() metho…

ISCC2014-reverse

这是我做reverse的题解。在咱逆向之路上的mark一下&#xff0c;&#xff0c;水平有限&#xff0c;大牛见笑。题目及题解链接&#xff1a;http://pan.baidu.com/s/1gd3k2RL 宗女齐姜 果然是仅仅有50分的难度&#xff0c;OD直接找到了flag. 找到杀手 这题用OD做非常麻烦。我改用I…

python 获取当前时间再往前几个月_Python 中的时间和日期操作

Python中,对日期和时间的操作,主要使用这3个内置模块: datetime 、 time 和 calendar 获取当前时间对应的数字 开发程序时,经常需要获取两个代码位置在执行时的时间差,比如,我们想知道某个函数执行大概耗费了多少时间,就可以使用time.time()来做。 import time before =…

Java BigDecimal restder()方法与示例

BigDecimal类的restder()方法 (BigDecimal Class remainder() method) Syntax: 句法&#xff1a; public BigDecimal remainder(BigDecimal divsr);public BigDecimal remainder(BigDecimal divsr, MathContext ma_co);remainder() method is available in java.math package.…

python程序需要编译么_python需要编译么

一个经常听见的问题&#xff0c;那就是&#xff1a;Python是解释型的语言吗&#xff1f;它会被编译吗&#xff1f;这个问题没有想象中那么好回答。和很多人认识世界一样&#xff0c;习惯以一个简单的模型去评判一些事物。而事实上&#xff0c;里面包含了很多很多的细节。通常的…

DevOps平台中的自动化部署框架设计

本文目录&#xff1a; 一、背景 二、我们的需求是什么&#xff1f; 三、概念澄清 四、概念模型 五、总体设计 六、关键点设计 七、总结 一、背景 说到自动化部署&#xff0c;大家肯定都会想到一些配置管理工具&#xff0c;像ansible,chef,puppet, saltstack等等。虽然这些工具给…

插入排序算法 ,递归实现_C程序实现递归插入排序

插入排序算法 ,递归实现The only difference between Insertion sort and Recursive Insertion Sort is that in the Recursive method, we start from placing the last element in its correct position in the sorted array instead of starting from the first. 插入排序和…

python虚拟机直接加载字节码运行程序_第二章 python如何运行程序

一.python解释器介绍Python解释器是一种让程序运行起来的程序。实际上&#xff0c;解释器是代码与机器的计算机硬件之间的软件逻辑层。当Python包安装在机器上后&#xff0c;它包含了一些最小化的组件&#xff1a;一个解释器和支持的库。二.python的视角当Python运行脚本时&…

Java LocalDate类| 带示例的format()方法

LocalDate类format()方法 (LocalDate Class format() method) format() method is available in java.time package. format()方法在java.time包中可用。 format() method is used to format this LocalDate object by using the given DateTimeFormatter object. format()方法…

胃癌2019csco指南_2019 CSCO胃癌诊疗指南精华来了!

一文轻松get 2019 CSCO胃癌诊疗指南更新要点&#xff01;文丨青青子衿 中山大学肿瘤防治中心来源丨医学界肿瘤频道近日&#xff0c;2019年CSCO指南发布会于南京召开。今天为大家推送的是2019 CSCO胃癌诊疗指南的最新更新&#xff0c;在发布专场中&#xff0c;来自华中科技大学同…

001_docker-compose构建elk环境

由于打算给同事分享elk相关的东西,搭建配置elk环境太麻烦了,于是想到了docker。docker官方提供了docker-compose编排工具,elk集群一键就可以搞定,真是兴奋。好了下面咱们开始吧。 一、 https://github.com/deviantony/docker-elk $ cd /006_xxxallproject/005_docker/001_e…

Java即时类| toString()方法与示例

即时类toString()方法 (Instant Class toString() method) toString() method is available in java.time package. toString()方法在java.time包中可用。 toString() method is used to represent this Instant as a String by using the standards ISO-8601 format. toString…

learn opengl 中文_LearnOpenGL CN

欢迎来到OpenGL的世界欢迎来到OpenGL的世界。这个工程只是我(Joey de Vries)的一次小小的尝试&#xff0c;希望能够建立起一个完善的OpenGL教学平台。无论你学习OpenGL是为了学业&#xff0c;找工作&#xff0c;或仅仅是因为兴趣&#xff0c;这个网站都将能够教会你现代(Core-p…

MYSQL5.7 日志管理

2019独角兽企业重金招聘Python工程师标准>>> 慢查询日志slow-query-log1 slow-query-log-filefile_name long_query_time1 #SQL执行多长时间以上会记录到慢查询日志&#xff0c;0~10s log_slow_admin_statementsOFF #在写入慢查询日志的语句中包含缓慢的管理语句。 …

duration java_Java Duration类| ofHours()方法与示例

duration javaDuration Class of Hours()方法 (Duration Class ofHours() method) ofHours() method is available in java.time package. ofHours()方法在java.time包中可用。 ofHours() method is used to represent the given hours in this Duration. ofHours()方法用于表示…

sumo的简单应用_sumo快速运行简单仿真实例详细教程

本文旨在让大家快速的了解sumo&#xff0c;并给出运行一个简单的sumo的例子的教程&#xff0c;进而了解基本sumo工程的架构&#xff0c;使大家对该软件产生兴趣并持续学习下去&#xff0c;刚开始学习仿真的确枯燥&#xff0c;项目“跑起来”才是大家学习下去的动力&#xff0c;…

stl vector 函数_vector :: crbegin()函数,以及C ++ STL中的示例

stl vector 函数C vector :: crbegin()函数 (C vector::crbegin() function) vector::crbegin() is a library function of "vector" header, it is used to get the last element of a vector using const_reverse_iterator, it returns a const reverse iterator …

ReactNative学习笔记(二)Flex布局

flexDirection 决定主轴方向 column&#xff1a;垂直方向为主轴row:水平方向为主轴justifyContent 决定主轴元素排列方式 flex-startflex-endcenterspace-betweenspace-aroundalignItems 决定侧轴元素排列方向 flex-startflex-endcenterbaselinestretch