浏览器的事件委托详解

了解事件机制首先要了解事件和事件流。

1. 事件处理程序

事件处理程序分为3类:

  • HTML事件处理程序
  • DOM0级事件处理程序
  • DOM2级事件处理程序

1. HTML事件处理程序

<button onclick="alert(hello world!)"></hello>

 特点是:

HTML和JS高度耦合;当需要修改函数名称时,需要同时修改两个地方

2. DOM0级事件处理程序

DOM0级事件处理程序指的是通过给DOM节点通过JS添加on[event]事件。

var btn=document.getElementById("#btn");
btn.onclick=function(){
    alert(hello world!)
}

特点是:

每个DOM只能添加一个事件;

3. DOM2级事件处理程序

其特点:

可以给DOM节点同时添加多个处理事件

IE10-对应的方法是:attachEvent/detachEvent,用法如下:

function handleEvent(event) {
   // TODO
}
dom.attachEvent(eventName, handleEvent)  // attachEvent只能在冒泡阶段和目标阶段触发
dom.detachEvent(eventName, handleEvent) 

其事件对象的获取可以直接在监听函数的参数中获取,其属性有:

1. type - 获取事件类型
2. srcElement - 获取目标对象
3. cancelBubble = true 阻止事件冒泡
4. returnValue = false 阻止事件的默认行为

 

IE11+及其他浏览器对应的方法是addEventListener/removeEventListener。其用法如下:

function handleEvent(event) {
  // TODO
}
dom.addEventListener(eventName, handleEvent , false); //  即{useCapture: false},可在冒泡阶段/目标阶段触发;默认值
dom.removeEventListener(eventName,  handleEvent, false);

其对应的事件对象的属性有:

1. type - 获取事件类型
2. target - 获取事件目标
3. stopPropagation() - 阻止事件传播
4. preventDefault() - 阻止事件的默认行为

2. 事件流

事件流是在页面中接受事件的顺序, 即事件传播的顺序。事件传播包含三个阶段:

  • 捕获阶段-从最外层->目标DOM
  • 目标阶段
  • 冒泡阶段-目标DOM->最外层

当冒泡和捕获同时存在时,事件触发顺序为:捕获->目标->冒泡

示例:

<!-- 单击son-->
<!DOCTYPE html>
<html lang="en">
<body>
  <div id="father" style="width: 400px;height: 200px;background-color: bisque">
    <div id="son" style="width: 200px; height: 100px;background-color: brown"></div>
  </div>
  <script>
    document.body.addEventListener('click', function(event) {
      console.log('body-bubble')
    }, false);
    // 注意不能直接将parent作为id,会代表window.parent
    father.addEventListener('click', function(event) {
      console.log('father-bubble');
    }, false);
    document.body.addEventListener('click', function(event) {
      console.log('body-capture')
    }, true);
    father.addEventListener('click', function(event) {
      console.log('father-capture');
    }, true);
    son.addEventListener('click', function(event) {
      console.log('son');
    }, false); 
  </script>
</body>
</html> 

运行结果

body-capture
father-capture
son
father-bubble
body-bubble

3. 事件委托

事件委托,也叫事件代理。

1. 事件委托的原理

一般指的是利用事件冒泡,将一个或者一组DOM的事件处理程序,委托给其父级元素或者更外层元素。

2. 事件委托的意义

可以通过只指定一个事件处理程序,就可以管理一批同类型的事件处理程序。

如果需要给列表项添加事件,当列表项数量过多时,会存在频繁操作DOM的情况;并且函数是引用类型, 需要堆内存来存储,占用大量空间。通过事件委托,可以将事件绑定到其父级元素ul上,这样只需要操作一次DOM,不会引起频繁的重绘。也不会占用大量的空间。

示例:

<!-- 通过事件的具体属性实现通过事件委托也和直接绑定在li上一样的效果--><!DOCTYPE html>
<html lang="en">
<body>
  <ul id='father'>
    <li id="a">A</li>
    <li id="b">B</li>
    <li id="c">C</li>
    <li id="d">D</li>
  </ul>
  <script>
  father.addEventListener('click', function(e) {
    const event = e || window.event;
    const target = event.target || event.srcElement;
    // 根据事件属性判断当前所在的DOM节点,不同节点处理不同的程序
    switch(target.id) {
      case "a":
        console.log('a');
        break;
      case "b":
        console.log('b');
        break;
      case "c":
        console.log("c");
        break;
      case "d":
        console.log("d");
        break;
      default:
        console.log('default');
    }
  })
  </script>
</body>
</html>

 

posted @ 2020-03-13 08:16  Lyra李  阅读(445)  评论(0编辑  收藏  举报