您的位置:首页 > 其它

关于事件的传播流程

2019-03-07 21:52 302 查看

谈谈在js中事件的传播流程

什么是事件?

  • HTML 事件是发生在 HTML 元素上的事情。

  • 当在 HTML 页面中使用 JavaScript 时, JavaScript 可以触发这些事件。

事件有可能是由用户发起的,比如鼠标事件,键盘事件,窗口事件,表单事件,也有可能是页面加载资源过程中的事件。常见的事件比如:click, dbclick, keydown, keypress, keyup, mousemove, wheel, scroll, focus, blur, load, unload, abort, error, resize, change, select, submit, 和这些及其相关的。

DOM事件流

  • DOM事件流存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡

事件冒泡和事件捕获

事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题。此处有一段代码

<div id="box">
<button id="btn">我是按钮</button>
</div>

事件冒泡

微软提出了名为事件冒泡(event bubbling)的事件流。事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。因此在事件冒泡的概念下在button元素上发生click事件的顺序应该是button -> div -> body -> html -> document

事件捕获

网景提出另一种事件流名为事件捕获(event capturing)。与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。因此在事件捕获的概念下在p元素上发生click事件的顺序应该是document -> html -> body -> div -> button

dom标准事件流的触发的先后顺序为:先捕获再冒泡,即当触发dom事件时,会先进行事件捕获,捕获到事件源之后通过事件传播进行事件冒泡。
但是不同的浏览器对此有着不同的实现,IE10及以下不支持捕获型事件,所以就少了一个事件捕获阶段,IE11、Chrome 、Firefox、Safari等浏览器则同时存在。

addEventListener的第三个参数

addEventListener的第三个参数就是为冒泡和捕获准备的.

addEventListener有三个参数:

element.addEventListener(event, function, useCapture)

第一个参数是需要绑定的事件第二个参数是触发事件后要执行的函数第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果参数为true,则表示在事件捕获阶段调用处理函数。

事件冒泡

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
div{
background: red;
width: 200px;
height: 200px;
}
button{
width: 100px;
height: 30px;
margin: 50px 0 0 50px;
}
</style>
</head>
<body>
<div id="box">
<button id="btn">我是按钮</button>
</div>
<script>

var parent = document.getElementById("box");
var child = document.getElementById("btn");

document.body.addEventListener("click",function(e){
console.log("click-body");
},false);

parent.addEventListener("click",function(e){
console.log("click-parent");
},false);

child.addEventListener("click",function(e){
console.log("click-child");
},false);
</script>
</body>
</html>

通过"addEventListener"方法,采用事件冒泡方式给dom元素注册click事件,点击子元素会发生什么呢?如果你对事件冒泡有一定了解的话那你肯定知道上面的代码会输出的顺序,没错,如下图所示:


事件触发顺序是由内到外的,这就是事件冒泡,虽然只点击子元素,但是它的父元素也会触发相应的事件,其实这是合理的,因为子元素在父元素里面,点击子元素也就相当于变相的点击了父元素,这样理解对吧?这里有同学可能要问了,如果点击子元素不想触发父元素的事件怎么办?肯定可以的,那就是停止事件传播—event.stopPropagation();

事件捕获

修改上面代码

var parent = document.getElementById("box");
var child = document.getElementById("btn");

document.body.addEventListener("click",function(e){
console.log("click-body");
},false);

parent.addEventListener("click",function(e){
console.log("click-parent---事件传播");
},false);
          //新增事件捕获事件代码
parent.addEventListener("click",function(e){
console.log("click-parent--事件捕获");
},true);

child.addEventListener("click",function(e){
console.log("click-child");
},false);

输出的结果:

父元素通过事件捕获的方式注册了click事件,所以在事件捕获阶段就会触发,然后到了目标阶段,即事件源,之后进行事件传播,parent同时也用冒泡方式注册了click事件,所以这里会触发冒泡事件,最后到根节点。这就是整个事件流程。

事件委托/代理

基本概念: 事件委托就是利用事件冒泡的原理,把事件加到父元素或祖先元素上,触发执行效果

事件委托优点1、提高JavaScript性能。事件委托可以显著的提高事件的处理速度,减少内存的占用。

试想一下,若果我们有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候响应一个事件;

<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
......
<li>item n</li>
</ul>
// ...... 代表中间还有未知数个 li

如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的,效率上需要消耗很多性能;因此,比较好的方法就是把这个点击事件绑定到他的父层,也就是

ul
上,然后在执行事件的时候再去匹配判断目标元素;所以事件委托可以减少大量的内存消耗,节约效率。

  1. 动态绑定事件

    比如上述的例子中列表项就几个,我们给每个列表项都绑定了事件;在很多时候,我们需要通过 AJAX 或者用户操作动态的增加或者去除列表项元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件;如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的;所以使用事件在动态绑定事件的情况下是可以减少很多重复工作的。

jQuery 中的事件委托

  • $.on: 基本用法: $(’.parent’).on(‘click’, ‘a’, function () { console.log(‘click event on tag a’); }),它是 .parent 元素之下的 a 元素的事件代理到 $(’.parent’) 之上,只要在这个元素上有点击事件,就会自动寻找到 .parent 元素下的 a 元素,然后响应事件;

  • $.delegate: 基本用法: $(’.parent’).delegate(‘a’, ‘click’, function () { console.log(‘click event on tag a’); }),同上,并且还有相对应的 $.delegate 来删除代理的事件;

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: