专栏首页OECOMjs事件流机制

js事件流机制

什么是事件流

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

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

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

事件绑定

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

<!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则代表接受捕获事件。)

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

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

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

属性

描述

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指代的是同一对象。

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

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

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

事件委托

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

如下:

<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内容,那么如果不用事件委托的话,应该是如下方法

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并没有添加上点击事件。

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

var link = document.getElementById("myLink");
link.addEventListener('click',function(e){
    if(!!e.target&&e.target.className=='child'){
console.log(e.target.innerHTML);
    }
})

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • input输入中文时,拼音触发input事件

    在上一篇文章中写到了函数防抖,在使用函数防抖来进行搜索框优化的时候会遇到一个问题,就是监听文本输入框的input事件,在拼写汉字(输入法)但汉字并未实际填充到文...

    无邪Z
  • 使用nodejs做文件下载中转

    之前做了一个功能就是点击按钮实现文件下载,文件保存在了阿里云的OSS上,阿里的OSS和七牛的OSS其实个人感觉差不多,一般情况下,前端下载文件很多都是通过一个a...

    无邪Z
  • 短链接原理及其算法实现

    短网址在目前来说是一个非常流行的东西,提供短网址服务的网站也是相当多的,短网址在微博上应用的比较广泛 ,因为微博对于url的长度有一个限制,所以将一个很长的网址...

    无邪Z
  • 后端开发实践系列——事件驱动架构(EDA)编码实践

    在本系列的前两篇文章中,我分别讲到了后端项目的代码模板和DDD编码实践,在本文中,我将继续以编码实践的方式分享如何落地事件驱动架构。

    ThoughtWorks
  • 关于堆

    Noneplus
  • Struts2再曝S2-020补丁绕过漏洞 – 万恶的正则表达式

    4月24日,网络曝出文章“安全研究人员指出Apache Struts2在漏洞公告S2-020里,在处理修复CVE-2014-0094的漏洞修补方案存在漏洞,导致...

    FB客服
  • 企业面试题: 实现一个事件委托(事件代理)

    考核内容: 事件委托:它还有一个名字叫事件代理,事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

    舒克
  • 事件流处理框架NEsper for .NET

    复合事件处理(Complex Event Processing)介绍提到了开源的Esper,NEsper 是一个事件流处理(Event Stream Proce...

    张善友
  • EMNLP 2019 | 常识信息增强的事件表示学习

    事件是现实世界中一种重要的知识,学习有效的事件表示可以提升脚本事件预测等许多下游任务的效果。事件是对客观事实的表达,然而客观事件的发生会对人类的主观情感产生影响...

    AI科技评论
  • 哈工大SCIR Lab | EMNLP 2019 常识信息增强的事件表示学习

    论文名称:Event Representation Learning Enhanced with External Commonsense Knowledge

    zenRRan

扫码关注云+社区

领取腾讯云代金券