详解JavaScript 事件流


Posted in Javascript onSeptember 02, 2020

事件

HTML中与javascript交互是通过事件驱动来实现的,例如鼠标点击事件、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。

事件流

事件流描述的就是从页面中接收事件的顺序。而早期的IE和Netscape提出了完全相反的事件流概念,IE事件流是事件冒泡,而Netscape的事件流就是事件捕获。

事件流类别

事件冒泡

即从下至上,从目标触发的元素逐级向上传播,直到window对象。

详解JavaScript 事件流

事件捕获

即从上至下,从document逐级向下传播到目标元素。

详解JavaScript 事件流

后来ECMAScript在DOM2中对事件流进行了进一步规范,基本上就是上述二者的结合。

DOM2级事件规定的事件流包括三个阶段:

  1. 事件捕获阶段
  2. 处于目标阶段
  3. 事件冒泡阶段

注意⚠️:先捕获后冒泡,但是在目标节点上谁写在前面谁先执行。但是在目标元素上不区分冒泡还是捕获,按绑定的顺序来执行。

详解JavaScript 事件流

DOM事件级别

分为四个级别

详解JavaScript 事件流

DOM0:不是W3C规范。

DOM1:开始是W3C规范。专注于HTML文档和XML文档。

DOM2:对DOM1增加了样式表对象模型

DOM3:对DOM2增加了内容模型 (DTD 、Schemas) 和文档验证。

DOM0级

DOM0级事件具有极好的跨浏览器优势,会以最快的速度绑定。绑定方式有如下两种

行内绑定(内联模型)

将函数名直接作为html标签中属性的属性值。

<div onclick="btnClick()">按钮</div>
<script>
function btnClick(){
  console.log("hello");
}
</script>

动态绑定(脚本模型)

通过在JS中选中某个节点,然后给节点添加onclick属性

<div id="btn">按钮</div>
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
  console.log("点击");
}
</script>

注意⚠️

  • DOM0级同一个节点只能添加一次同类型事件,后添加的同类型事件会覆盖前面的事件
  • DOM0级只支持冒泡

DOM1级

其中DOM1级事件处理标准中并没有定义事件相关的内容,所以没有所谓的DOM1事件处理

DOM2级

DOM2级定义了两个事件处理程序。(观察者模式)

  • addEventListener() ---添加事件侦听器
  • removeEventListener() ---删除事件侦听器

函数均有3个参数, 第一个参数是要处理的事件名 第二个参数是作为事件处理程序的函数 第三个参数是一个boolean值,默认false表示使用冒泡机制,true表示捕获机制。

<div id="btn">按钮</div>
<script>
var btn=document.getElementById("btn");
btn.addEventListener("click",hello,false);
btn.addEventListener("click",helloagain,false);
function hello(){
  console.log("hello");
}
function helloagain(){
  console.log("hello again");
}
</script>
// 点击后结果: 
// hello
// hello again

注意⚠️

如果定义了一模一样的监听方法时,是会发生覆盖的。

<div id="btn">点击</div>

<script>
var btn=document.getElementById("btn");
btn.addEventListener("click",hello,false);
btn.addEventListener("click",hello,false);
function hello(){
  console.log("hello");
}
</script>
// 点击后结果: 
// hello

DOM3级

对DOM2增加了内容模型 (DTD 、Schemas) 和文档验证。定义了一些新的事件,比如键盘事件,还可以自定义事件。

自定义事件

自定义事件不是由DOM原生触发的,它的目的是让开发人员创建自己的事件。要创建的自定义事件可以由createEvent("CustomEvent"); 返回的对象有一个initCustomEvent()方法接收如下四个参数。

  • type:字符串,触发的事件类型,自定义。例如 “keyDown”,“selectedChange”;
  • bubble(布尔值):标示事件是否应该冒泡;
  • cancelable(布尔值):标示事件是否可以取消;
  • detail(对象):任意值,保存在event对象的detail属性中;

可以像分配其他事件一样在DOM中分派创建的自定义事件对象。如:

var div = document.getElementById("myDiv");
EventUtil.addEventHandler(div,"myEvent", function () {
 alert("div myEvent!");
});
EventUtil.addEventHandler(document,"myEvent",function(){
 alert("document myEvent!");
});
if(document.implementation.hasFeature("CustomEvents","3.0")){
 var e = document.createEvent("CustomEvent");
 e.initCustomEvent("myEvent",true,false,"hello world!");
 div.dispatchEvent(e);
}

这个例子中创建了一个冒泡事件“myEvent”。而event.detail的值被设置成了一个简单的字符串,然后在div和document上侦听该事件,因为在initCustomEvent中设置了事件冒泡。所以当div激发该事件时,浏览器会将该事件冒泡到document。

阻止冒泡

stopPropagation函数

btn.addEventListener('click',function(ev){
  ev.stopPropagation();
  console.log('阻止冒泡')
}, false)

事件委托(事件代理)

原理

如果有多个DOM节点需要监听事件的情况下,给每个DOM绑定监听函数,会极大的影响页面的性能,因为我们通过事件委托来进行优化,事件委托利用的就是冒泡的原理。

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>
<script>
  var li_list = document.getElementsByTagName('li')
  for(let index = 0;index<li_list.length;index++){
    li_list[index].addEventListener('click', function(ev){
      console.log(ev.currentTarget.innerHTML)
    })
  }
</script>

正常情况我们给每一个li都会绑定一个事件,但是如果这时候li是动态渲染的,数据又特别大的时候,每次渲染后(有新增的情况)我们还需要重新来绑定,又繁琐又耗性能;这时候我们可以将绑定事件委托到li的父级元素,即ul。

var ul_dom = document.getElementsByTagName('ul')
ul_dom[0].addEventListener('click', function(ev){ 
  console.log(ev.target.innerHTML)
})

target和currentTarget区别:

  • target返回触发事件的元素,不一定是绑定事件的元素
  • currentTarget返回的是绑定事件的元素

优点

  • 提高性能: 每一个函数都会占用内存空间,只需添加一个事件处理程序代理所有事件,所占用的内存空间更少。
  • 动态监听: 使用事件委托可以自动绑定动态添加的元素,即新增的节点不需要主动添加也可以一样具有和其他元素一样的事件。

以上就是详解JavaScript 事件流的详细内容,更多关于JavaScript 事件流的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JSON 入门指南 想了解json的朋友可以看下
Aug 26 Javascript
aspx中利用js实现确认删除代码
Jul 22 Javascript
基于jQuery的为attr添加id title等效果的实现代码
Apr 20 Javascript
JQuery与JSon实现的无刷新分页代码
Sep 13 Javascript
js不间断滚动的简单实现
Jun 03 Javascript
ES6概念 Symbol.keyFor()方法
Dec 25 Javascript
一篇文章搞定JavaScript类型转换(面试常见)
Jan 21 Javascript
从零学习node.js之利用express搭建简易论坛(七)
Feb 25 Javascript
JavaScript中object和Object的区别(详解)
Feb 27 Javascript
JavaScript实现指定数量的并发限制的示例代码
Mar 10 Javascript
el-form 多层级表单的实现示例
Sep 10 Javascript
Vue中强制组件重新渲染的正确方法
Jan 03 Vue.js
JavaScript判断数据类型有几种方法及区别介绍
Sep 02 #Javascript
jQuery中getJSON跨域原理的深入讲解
Sep 02 #jQuery
JavaScript交换变量常用4种方法解析
Sep 02 #Javascript
Vue-cli打包后部署到子目录下的路径问题说明
Sep 02 #Javascript
Jquery $.map使用方法实例详解
Sep 01 #jQuery
JQuery基于FormData异步提交数据文件
Sep 01 #jQuery
vue实现路由懒加载的3种方法示例
Sep 01 #Javascript
You might like
jquery 插件学习(五)
2012/08/06 Javascript
javascript页面上使用动态时间具体实现
2014/03/18 Javascript
如何判断微信内置浏览器(通过User Agent实现)
2014/09/01 Javascript
jQuery中appendTo()方法用法实例
2015/01/08 Javascript
JavaScript中的对象和原型(一)
2016/08/12 Javascript
js对字符串进行编码的方法总结(推荐)
2016/11/10 Javascript
Javascript this 函数深入详解
2016/12/13 Javascript
JavaScript中在光标处插入添加文本标签节点的详细方法
2017/03/22 Javascript
Node.js 使用递归实现遍历文件夹中所有文件
2017/09/18 Javascript
vue弹窗插件实战代码
2018/09/08 Javascript
JavaScript函数IIFE使用详解
2019/10/21 Javascript
vue 实现动态路由的方法
2020/07/06 Javascript
vue动画—通过钩子函数实现半场动画操作
2020/08/09 Javascript
原生js实现自定义消息提示框
2020/11/19 Javascript
[01:03:50]DOTA2-DPC中国联赛 正赛 CDEC vs DLG BO3 第二场 2月7日
2021/03/11 DOTA
haskell实现多线程服务器实例代码
2013/11/26 Python
详解Python map函数及Python map()函数的用法
2017/11/16 Python
django上传图片并生成缩略图方法示例
2017/12/11 Python
python浪漫表白源码
2019/04/05 Python
python3.5安装python3-tk详解
2019/04/26 Python
Django 全局的static和templates的使用详解
2019/07/19 Python
python将时分秒转换成秒的实例
2019/12/07 Python
用python给csv里的数据排序的具体代码
2020/07/17 Python
Pycharm中使用git进行合作开发的教程详解
2020/11/17 Python
animation和transition的区别
2020/10/12 HTML / CSS
英国女性时尚鞋类的潮流制造者:Koi Footwear
2018/10/19 全球购物
巴基斯坦购物网站:Goto
2019/03/11 全球购物
在线实验室测试:HealthLabs.com
2020/05/03 全球购物
EJB发布WEB服务一般步骤
2012/10/31 面试题
大学毕业生的自我鉴定
2013/11/30 职场文书
优秀团员事迹材料1000字
2014/08/20 职场文书
2014年业务工作总结
2014/11/17 职场文书
煤矿安全生产管理协议书
2016/03/22 职场文书
Elasticsearch 配置详解
2022/04/19 Java/Android
阿里云服务器部署RabbitMQ集群的详细教程
2022/06/01 Servers
python库Tsmoothie模块数据平滑化异常点抓取
2022/06/10 Python