每天一道面试题 --- js事件代理和冒泡

Q:解释一下事件代理。
A:当我们需要对很多事件添加事件的时候,可以通过将事件添加到他们的父节点而将事件委托给父节点来触发处理函数,这主要得益于浏览器的事件冒泡机制。

  var delegate = function(client, clientMethod) {
      return function() {
          return clientMethod.apply(client, arguments);
      }
  }

  var agentMethod = delegate (client, clientMethod);
  agentMethod();

下面我们通过实例来详细的解释事件代理

假设有一个ul 的父节点,包含了很多的 li 子节点:

<ul id="parent-list">
  <li id="post-1">Item 1</li>
  <li id="post-2">Item 2</li>
  <li id="post-3">Item 3</li>
  <li id="post-4">Item 4</li>
  <li id="post-5">Item 5</li>
  <li id="post-6">Item 6</li>
</ul>

当我们把鼠标移到 li 上面的时候,需要获取此 li 的相关信息,并飘出悬浮窗口以显示详细信息,或者当某个 li 被点击的时候需要触发相应的处理事件,我们通常的写法,是为每个 li 都添加一些类似 onMouseOver 和 onClick 之类的事件监听。

function addListeners4Li(liNode){
    liNode.onclick = function clickHandler(){...};
    liNode.onmouseover = function mouseOverHandler(){...}
}

window.onload = function(){
    var ulNode = document.getElementById("parent-list");
    var liNodes = ulNode.getElementByTagName("Li");
    for(var i=0, l = liNodes.length; i < l; i++){
        addListeners4Li(liNodes[i]);
    }   
}

如果这个 ul 中的 li 子元素会频繁的添加或者删除,我们就需要在每次添加 li 的时候都调用这个 addListeners4Li 方法来为每个 li 节点添加事件处理函数。会提高复杂度,并且有出错的可能。

从而引出事件代理机制。当时间被抛到更上一层的父节点的时候,我们通过检查事件的目标对象 (target) 来判断并获取事件源 li ,代码如下。

// 获取父节点,并为它添加一个click事件
document.getElementById("parent-list").addEventListener("click",function(e) {
  // 检查事件源e.targe是否为Li
  if(e.target && e.target.nodeName.toUpperCase == "LI") {
    // 真正的处理过程在这里
    console.log("List item ",e.target.id.replace("post-")," was clicked!");
  }
});

为父节点添加一个click 事件,当子节点被点击的时候,click 事件会从子节点开始向上冒泡。父节点捕获到事件之后,通过 e.target.nodeName 来判断是否为我们需要处理的节点,并且通过 e.target 拿到被点击的 li 节点,从而可以获取到相应的信息,并做处理。

事件冒泡和捕获

对于事件的捕获和处理,不同的浏览器厂商有不同的处理机制,这里我们主要介绍W3C对DOM2.0定义的标准事件。
在这里插入图片描述

DOM2.0模型将事件处理流程分为三个阶段:一、事件捕获阶段,二、事件目标阶段,三、事件起泡阶段。如图:
在这里插入图片描述
事件捕获:当某个元素触发某个事件(如 onclick),顶层对象 document 就会发出一个事件流,随着 DOM 树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。
事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数,如果没有绑定监听函数,那就不执行。
事件冒泡:从目标元素开始,往顶层元素传播,途中如果有节点绑定了相应的事件处理函数,这些函数就会被依次触发。如果想阻止事件冒泡,可以使用 e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来阻止事件的冒泡传播。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值