前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >js事件流机制

js事件流机制

作者头像
OECOM
发布2020-07-01 17:02:44
1.5K0
发布2020-07-01 17:02:44
举报
文章被收录于专栏:OECOMOECOM

什么是事件流

在JavaScript中事件流是指一个事件沿特定数据结构传播的一个过程。整个事件流总共包含三个阶段(从dome2来说):1.事件捕获阶段、2.处于事件目标阶段、3.事件冒泡阶段。下面我们来看一个图,只要是谈到事件流都会看到的一个图:

js事件流机制
js事件流机制

从这个图里面我们可以清晰的看到整个事件流的执行过程,首先是从window开始,一步步的从上向下执行,此过程就是事件捕获阶段,当到达了事件的位置以后则处于事件目标阶段,之后会在向上冒泡,进入事件的冒泡阶段。

你可以吧整个dom看做是一盆水,水里放密度不同的物品,有的物品可以嵌在其他物品中,构成父子节点,有的相互独立,构成兄弟节点,当你的手从上去点你需要点的物品时,势必要先触碰水面,然后触碰到父节点,然后才是目标节点。触碰完成以后再把手拿出来,正好是一个相反的过程,这就与我们的事件流机制是一个道理。

事件绑定

下面来看一下下面这个示例代码:

代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style type="text/css">
         #p { width: 300px; height: 300px; padding: 10px;  border: 1px solid black; }
         #c { width: 100px; height: 100px; border: 1px solid red; }
         #d { width: 50px; height: 50px; border: 1px solid green; }
    </style>
</head>
<body>
    <div id="p">
        parent
        <div id="c">
            <div id="d">
                grant
            </div>
            child
        </div>
    </div>
    <script type="text/javascript">
        var p = document.getElementById('p'),
        c = document.getElementById('c'),
        d = document.getElementById('d');
         p.addEventListener('click', function () {
            alert('父节点捕获')
        },true);

        p.addEventListener('click', function () {
            alert('父节点冒泡')
        });
        c.addEventListener('click', function () {
            alert('子节点捕获')
        },true);

        c.addEventListener('click', function (e) {
            alert('子节点冒泡')
        });
        d.addEventListener('click', function () {
            alert('孙子节点捕获')
        },true);

        d.addEventListener('click', function (e) {
            alert('孙子节点冒泡')
        });
    </script>
</body>
</html>

点击ID为d的元素,你会发现依次弹出的内容为:父节点捕获-->子节点捕获-->孙子节点捕获-->孙子节点冒泡-->子节点冒泡-->父节点冒泡。(在添加注册事件时,第三个参数为true则代表接受捕获事件。)

在上面的代码中我们稍作修改

代码语言:javascript
复制
d.addEventListener('click', function (e) {
            alert('孙子节点捕获');
            console.log(e);
        },true);
js事件流机制
js事件流机制

打印结果如上图所示。下面我们看一下一些常用的属性含义

属性

描述

DOM

bubbles

返回布尔值,指示事件是否是起泡事件类型。

2

cancelable

返回布尔值,指示事件是否可拥可取消的默认动作。

2

currentTarget

返回其事件监听器触发该事件的元素。

2

eventPhase

返回事件传播的当前阶段。调用事件处理程序的阶段:1 捕获;2 处于阶段;3 冒泡阶段;这个属性的变化需要在断点中查看,不然你看到的总是0

2

target

返回触发此事件的元素(事件的目标节点)。

2

timeStamp

返回事件生成的日期和时间。

2

type

返回当前 Event 对象表示的事件的名称。

2

view

与事件关联的抽象视图,发生事件的window对象

2

preventDefault

取消事件默认行为,cancelable是true时可以使用

2

stopPropagation

取消事件捕获/冒泡,bubbles为true才能使用

2

stopImmediatePropagation

取消事件进一步冒泡,并且组织任何事件处理程序被调用

3

在事件程序中,this和currentTarget指代的是同一对象。

如果说在事件捕获阶段,将子节点移除,那么子节点的捕获和冒泡是否还会执行?那么在上面的代码中我们在做一些修改,来查看一下效果

代码语言:javascript
复制
 c.addEventListener('click', function () {
            alert('子节点捕获');
            c.removeChild(d);
        },true);

运行后我们发现,执行顺序没有变化,子节点的捕获和冒泡依然执行,这里就需要我们做一些优化了,不仅要移除子节点,还需要对节点的注册事件进行移除。

事件委托

不知道大家在平时的使用的时候有没有遇到过这样的一种情况,如果事件涉及到更新HTML节点或者添加HTML节点的时候,就会出现这样的一种情况,新添加的节点无法绑定事件,更新的节点也是无法绑定事件,表现的行为是无法触发事件

如下:

代码语言:javascript
复制
<button id="e">增加</button>
<ul id='myLink'>
  <li class="child"> apple </li>
  <li class="child"> banana </li>
  <li class="child"> orange </li>
</ul>
e = document.getElementById('e');
        e.addEventListener('click',function(){
            var myLink = document.getElementById('myLink');
            var child =document.createElement("li");
            child.className="child";
            child.innerText ="orange"
            myLink.appendChild(child)
        })

有个需求是点击li需要打印出其html内容,那么如果不用事件委托的话,应该是如下方法

代码语言:javascript
复制
function shuchu(){
    this.init();
}

Contact.prototype.init = function(){
    var child = document.querySelectorAll('.child');
    for(var i=0;i<child.length;i++){
        (function(j){
            child[j].onclick = function(){
                    console.log(child[j].innerText);
            }
        })(i);
    }
}
new shuchu();

我们会发现一个问题,就是每一个li都添加了一个监听事件,这样如果说li数量非常大的话就会产生性能问题,甚至造成页面卡顿崩溃,另一方面就是新增加的li并没有添加上点击事件。

如果用事件委托,则会很好的解决这两个问题

代码语言:javascript
复制
var link = document.getElementById("myLink");
link.addEventListener('click',function(e){
    if(!!e.target&&e.target.className=='child'){
console.log(e.target.innerHTML);
    }
})

事件委托采用注册一个事件则能监听子节点的所有事件,所应用的就是事件的冒泡。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-11-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 事件绑定
  • 事件委托
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档