【前端知识之JS】JS中的事件模型和事件代理

前言

本系列主要整理前端面试中需要掌握的知识点。本节介绍 JS中的事件模型和事件代理 。


一、事件与事件流

事件:在HTML文档或者浏览器中发生的一种交互操作,使得网页具备互动性,常见的有加载事件、鼠标事件、自定义事件。
事件流:由于DOM是个树结构,如果在父子节点绑定事件时候,当触发子节点的时候,就存在一个顺序的问题,这就是事件流。
事件流都会经历的三个阶段

  • 事件捕获阶段;
  • 处于目标阶段;
  • 事件冒泡阶段。
    在这里插入图片描述
    事件冒泡:一种从下往上的传播方式,由最具体的元素然后逐渐向上传播到最不具体的那个节点,也就是DOM的高层的父节点。
<body>
    <button id="btn">Click me!</button>
</body>

<script>
    var btn = document.getElementById('btn');

    btn.onclick = function(){
        console.log("1.Button");
    }
    document.body.onclick = function(){
        console.log("2.Body");
    }
    document.onclick = function(){
        console.log("3.document");
    }
    window.onclick = function(){
        console.log("4.window");
    }
</script>

点击后:
在这里插入图片描述

二、事件模型

1. 原始事件模型(DOM0级)

  • HTML代码中直接绑定
<input type="button" onclick="fun()">
  • 通过JS代码绑定
var btn = document.getElementById('.btn');
btn.onclick = fun;

特性

  • 绑定速度快:但由于绑定速度太快,可能页面还未完全加载出来,以至于事件可能无法正常运行;
  • 只支持冒泡,不支持捕获;
  • 同一个类型的事件只能绑定一次

2. 标准事件模型(DOM2级)

  • 事件捕获阶段:事件从document一直向下传播到目标元素,依次检查经过的节点是否绑定了事件监听函数,如果有则执行;
  • 事件处理阶段:事件到达目标元素,触发目标元素的监听函数;
  • 事件冒泡阶段:事件从目标元素冒泡到document,依次检查经过的节点是否绑定了监听函数,如果有则执行。
  • 绑定监听:addEventListener(eventType, handler, useCapture)
  • 移除监听:removeEventListener(eventType, handler, useCapture)
var btn = document.getElementById('.btn');
btn.addEventListener(‘click’, showMessage, false);
btn.removeEventListener(‘click’, showMessage, false);

特性

  • 可以在一个DOM元素上绑定多个事件处理器,各自并不会冲突
btn.addEventListener(‘click’, showMessage1, false);
btn.addEventListener(‘click’, showMessage2, false);
btn.addEventListener(‘click’, showMessage3, false);
  • 当第三个参数设置为true就在捕获过程中执行,反之在冒泡过程中执行

3. IE事件模型(基本不用)

  • 事件处理阶段:事件到达目标元素, 触发目标元素的监听函数。
  • 事件冒泡阶段:事件从目标元素冒泡到document, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行。
  • 绑定监听:attachEvent(eventType, handler)
  • 移除监听:detachEvent(eventType, handler)
  • 例如
var btn = document.getElementById('.btn');
btn.attachEvent(‘onclick’, showMessage);
btn.detachEvent(‘onclick’, showMessage);

三、事件委托

1. 事件委托是什么

事件委托:就是把一个元素响应事件的函数委托到另一个元素,具体来说,会把一个或者一组元素的事件委托到它的父层,或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素。

2. 事件委托的应用场景

如果有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候响应一个事件。如果给每个列表项都绑定事件的话,会有很多重复的操作,因此可以绑定他们的父元素。

document.getElementById('list').addEventListener('click',function(e){
    var event = e || window.event;
    var target = event.target || event.srcElement;

    if(target.nodeName.toLocaleLowerCase() === 'li'){
        console.log('the content is:',target.innerHTML);
    }
})

动态添加元素:

<body>
    <button id="btn">添加新元素</button>
    <ul id="list">
        <li>item 1</li>
        <li>item 2</li>
        <li>item 3</li>
        <li>item 4</li>
        <li>item 5</li>
    </ul>
</body>

<script>
    const btn = document.getElementById("btn");
    const list = document.getElementById("list");
    var num = 5;

    list.onclick = function(e){
        var event = e || window.event;
        var target = event.target || event.srcElement;
 
        if(target.nodeName.toLocaleLowerCase() === 'li'){
            console.log('the content is:',target.innerHTML);
        }
    }

    btn.onclick = function(){
        num++;
        const newlist = document.createElement('li');
        newlist.innerHTML = `item ${num}`;
        list.appendChild(newlist);
    }
</script>

3. 事件委托的注意点

  • 适合事件委托的事件有:click, mousedown, mouseup, keydown, keyup, keypress;
  • focus, blur这些事件没有事件的冒泡机制,所以无法进行委托绑定事件;
  • mousemove, mouseout这样的事件虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,因此不适合做事件委托;
  • 如果把所有事件都用事件代理,可能会出现事件误判,即本不该被触发的事件被绑定上了事件。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值