基础知识--javascript事件机制与事件委托

事件:

事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。javascript与HTML之间的交互就是通过事件来实现的。观察者模型:使用侦听器或处理程序要预定时间,以便时间发生时执行相应的代码,这种模型支持页面的行为(javascript)与页面的外观(HTML和CSS)之间的松散耦合。

事件监听器与处理程序:

  • 响应某个事件的函数就叫做事件处理程序或事件监听器。在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息,包括导致事件的元素,事件 的类型以及其他与特定事件相关的信息,这个对象不需要定义,可以直接使用。
  • 事件处理程序:事件处理程序的名字以on开头,类似click、load、和 mouseover都是事件的名字,因此,click的事件处理程序就是onclick。案例如下:onclick就是事件处理程序
<div id="child" style="width: 90px;height:90px;background-color: cyan;margin: 0 auto;" onclick="showMessage(event)" >孩子</div>
<script type="text/javascript">
    function showMessage(event){
        alert(event.target.id);
    }
 </script> 
  • 事件监听器:例子如下:child.addEventListener("click",function (),true)是将指定的监听器注册到child上,当该对象触发指定的事件时,指定的回调函数就会被执行。
<div id="child" style="width: 90px;height:90px;background-color: cyan;margin: 0 auto;" >孩子</div>
<script type="text/javascript">
    let child = document.getElementById("child");
    /**
     *  事件监听器
     *  addEventListener(eventName , dealEventFunc , boolean)
     *  eventName: 要处理的事件名
     *  dealEventFunc: 作为事件处理程序的函数
     *  boolean: true表捕获事件,false表冒泡事件
     * */
    // 捕获事件流
    child.addEventListener("click",function () {
        //取消冒泡
        //event.stopPropagation();          //IE
        //event.cancelBubble = true;        //w3c
        console.log("捕获事件流:click child!");
    },true);
    //冒泡事件流
    child.addEventListener("click",function () {
        console.log("冒泡事件流:click child!");
    },false);
</script>

事件流:

  • 构建一棵dom树如下:
image.png
  1. IE事件流:事件冒泡流。

事件开始时由最具体的元素(文档中嵌到层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

image.png
  • 点击child<div>,显示如下:
image.png
  • 点击parent<div>,显示如下:
image.png
  1. NetSpace事件流:事件捕获流。

事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件,事件捕获的用意在于在事件到达预定目标之前捕获他。

image.png
  • 点击child<div>,显示如下:
image.png
  • 点击parent<div>,显示如下:
image.png
  1. DOM事件流:包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。

DOM2级事件规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会,然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。

下图,捕获阶段:1,2,3,4

处于目标阶段在事件处理中被看成是冒泡阶段的一部分

然后冒泡事件发生:5,6,7,8,9

image.png

阻止事件冒泡

        event.stopPropagation();          //IE
        event.cancelBubble = true;        //w3c
image.png

事件委托

  • 内存和性能:在javascript中,添加到页面上的时间处理程序数量将直接影响到页面的整体运行性能。导致这一问题的原因是多方面的,首先,每个函数都是对象,都会占用内存;内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。
  • 事件委托:事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。使整个页面只有少量的函数,从而优化页面性能。实例代码如下:
<!DOCTYPE html>
<html lang="en" id="html" onclick="clickDiv(event)">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body id="body">
<div id="grandparent" style="width: 270px;height:270px;background-color: blue; margin: 0 auto; text-align: center;line-height: 3">祖父
    <div id="parent" style="width: 180px;height:180px;background-color: cadetblue;margin: 0 auto;">父亲
        <div id="child" style="width: 90px;height:90px;background-color: cyan;margin: 0 auto;" >孩子
        </div>
    </div>
</div>
</body>
<script type="text/javascript">
    let child = document.getElementById("child");
    let parent = document.getElementById("parent");
    let grandparent = document.getElementById("grandparent");
    let body = document.getElementById("body");
    let html = document.getElementById("html");
    function clickDiv(event){
        switch (event.target.id){
            case 'child':console.log("click child!");break;
            case 'parent':console.log("click parent!");break;
            case 'grandparent':console.log("click grandparent!");break;
            case 'body':console.log("click body!");break;
            case 'html':console.log("click html!");break;
        }
    }
</script>
</html>
  • <html>标签中添加了onclick(event)事件处理程序。由于其他标签都是<html>的子节点,而且他们的事件会冒泡,所以单击事件终会被这个函数处理,点击各个点的输出情况如下所示。与给每个节点加一个处理程序相比,这种方法需要占用的内存更少,只添加了一个处理程序,虽然对用户来说最终结果都相同,但这种技术需要占用的内存更少,所有用到按钮的事件都适合采用事件委托技术
image.png
  • 如果可行的话,也可以考虑为document对象添加一个事件处理程序,用以处理页面上发生的某种特定类型的事件,这样做与传统的做法相比具有如下优点:
    1. document对象很快就可以访问,而且可以在生命周期的任何时间点上为它添加事件处理程序。‘
    2. 在页面中设置事件处理程序所需的时间更少,只添加体格事件处理程序所需的DOM引用更少,所花的时间也更少。
    3. 真个页面占用的内存空间更少,能够提升整体性能。
  • 整个demo代码:
<!DOCTYPE html>
<html lang="en" id="html" onclick="clickDiv(event)">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body id="body">
<div id="grandparent" style="width: 270px;height:270px;background-color: blue; margin: 0 auto; text-align: center;line-height: 3">祖父
    <div id="parent" style="width: 180px;height:180px;background-color: cadetblue;margin: 0 auto;">父亲
        <div id="child" style="width: 90px;height:90px;background-color: cyan;margin: 0 auto;" >孩子
        </div>
    </div>
</div>
<!--<div id="child" style="width: 90px;height:90px;background-color: cyan;margin: 0 auto;" onclick="showMessage(event)" >孩子-->
<!--</div>-->
</body>
<script type="text/javascript">
    let child = document.getElementById("child");
    let parent = document.getElementById("parent");
    let grandparent = document.getElementById("grandparent");
    let body = document.getElementById("body");
    let html = document.getElementById("html");

    //采用事件委托优化性能
    function clickDiv(event){
        switch (event.target.id){
            case 'child':console.log("click child!");break;
            case 'parent':console.log("click parent!");break;
            case 'grandparent':console.log("click grandparent!");break;
            case 'body':console.log("click body!");break;
            case 'html':console.log("click html!");break;
        }
    }
    // function showMessage(event){
    //     alert(event.target.id);
    // }
    /**
     *  事件监听器
     *  addEventListener(eventName , dealEventFunc , boolean)
     *  eventName: 要处理的事件名
     *  dealEventFunc: 作为事件处理程序的函数
     *  boolean: true表捕获事件,false表冒泡事件
     * */
    // 捕获事件流
    // child.addEventListener("click",function () {
    //     console.log("捕获事件流:click child!");
    // },true);
    // parent.addEventListener("click",function () {
    //     console.log("捕获事件流:click parent!");
    // },true);
    // grandparent.addEventListener("click",function () {
    //     console.log("捕获事件流:click grandparent!");
    // },true);
    // body.addEventListener("click",function () {
    //     console.log("捕获事件流:click body!");
    // },true);
    // html.addEventListener("click",function () {
    //     console.log("捕获事件流:click html!");
    // },true);
    // document.addEventListener("click" , function () {
    //     console.log("捕获事件流:click document!")
    // },true);
    // window.addEventListener("click" , function (ev) {
    //     console.log("捕获事件流:click window!")
    // },true);

    //冒泡事件流
    // child.addEventListener("click",function (event) {
    //     console.log("冒泡事件流:click child!");
    //     //阻止冒泡行为
    //     //event.stopPropagation();          //IE
    //     event.cancelBubble = true;        //w3c
    // },false);
    // parent.addEventListener("click",function () {
    //     console.log("冒泡事件流:click parent!");
    // },false);
    // grandparent.addEventListener("click",function () {
    //     console.log("冒泡事件流:click grandparent!");
    // },false);
    // body.addEventListener("click",function () {
    //     console.log("冒泡事件流:click body!");
    // },false);
    //
    // html.addEventListener("click",function () {
    //     console.log("冒泡事件流:click html!");
    // },false);
    // document.addEventListener("click" , function () {
    //     console.log("冒泡事件流:click document!");
    // },false);
    // window.addEventListener("click" , function (ev) {
    //     console.log("冒泡事件流:click window!");
    // },false);
</script>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • js之事件机制 1、事件初探 1.1 js事件的概述 JavaScript事件:JavaScript是基于事件驱动...
    道无虚阅读 2,331评论 1 3
  • JavaScript 程序采用了异步事件驱动编程模型。在这种程序设计风格下,当文档、浏览器、元素或与之相关的对象发...
    劼哥stone阅读 1,250评论 3 11
  • JavaScript 与 HTML 之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬...
    threetowns阅读 339评论 0 0
  • 关于Glide+RecyclerView图形错乱和闪烁 在RecyclerView中使用Glide加载图片,当图片...
    l1zheng阅读 3,516评论 0 0
  • 在写spark代码的时候,经常会遇到文件夹路径存在的情况,一般有以下的解决方式 1.在shell脚本中 直接调用h...
    刘凯歌阅读 3,363评论 0 0