Skip to content

概述

事件委托也叫事件代理,就是把目标节点的事件绑定到祖先节点上。基于事件传播过程,逐层冒泡总能被祖先节点捕获。可以只指定一个事件处理程序,就可以管理某一类型的所有事件。这样的好处是省监听数,可以监听动态元素。

举个例子,公司里有个三个同事预计在同一天收到快递。为签收快递,有两种方法:一、三个人在公司门口等快递;二、委托给前台代为签收。

现实生活中我们一般采用委托的方案。前台收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台也会在收到寄给新员工的快递后核实并代为签收。

这里其实有两层意思:

第二,新员工也是可以被前台代为签收的,即程序中新添加的dom节点也是有事件的。

使用场景

  • 场景一 很多的dom需要添加事件处理,比如100个按钮添加点击事件,每个按钮都有相同的点击事件,然而这样就需要遍历所有的按钮,来给他们给他们添加事件。

这样就会延长整个页面交互就绪时间,我们只需要监听这100个按钮的祖先,等冒泡的时候判断target是不是这个100个按钮中的一个。

//div为100个button的祖先元素
div.addEventLister('click',(e)=>{
  const t = e.target
  if(t.tagName.toLowerCase()==='button'){
    console.log('button data-id 是'+ t.dataset.id);
    console.log('button 内容是'+ t.textContent);
  }
})
  • 场景二 要监听不存在的元素点击事件,即还没有元素还没有被添加进去。
//div里延时创建一个button
setTimeout(() => {
  const button = document.createElement('button')
  button.textContent = 'click'
  div.appendChild(button)
}, 1000);

div.addEventListener('click',(e)=>{
  const t = e.target
  if(t.tagName.toLowerCase()==='button'){
    console.log('button :'+t.textContent);
  }
})

原理

事件委托利用了冒泡原理来实现,即事件从最深的节点开始,然后逐步向上传播事件。

封装事件委托

有一个自己定义的on函数,当用户点击#div里的button时调用。

on('click','#div','button',()=>{
  console.log('button被点击');
})
function on(eventType,element,selector,fn){
  if(!(element instanceof Element)){
    element = document.querySelector(element)
  }//判断是不是个元素,不是则去找这个元素
  element.addEventListener(eventType,(e)=>{
    const t = e.target
    if(t.matches(selector)){
      fn(e)
    }
  })
}

JS不支持事件,JS只是调用DOM提供的addEventListener。

其他内容

targetcurrentTarget的区别:

  • e.target——用户操作的元素
  • e.currentTarget——程序员监听的元素

手写一个可以拖动的div

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>JS Bin</title>
  </head>
  <body>
    <div id="xxx"></div>
  </body>
  <style>
    div{
    border: 1px solid red;
    position: absolute;
    top: 0;
    left: 0;
    width: 100px;
    height: 100px;
    }

    *{margin:0; padding: 0;}
  </style>
  <script>
  var dragging = false
  var position = null

  xxx.addEventListener('mousedown',function(e){
    dragging = true
    position = [e.clientX, e.clientY]
  })

  document.addEventListener('mousemove', function(e){
    if(dragging === false){return}
    console.log('hi')
    const x = e.clientX
    const y = e.clientY
    const deltaX = x - position[0]
    const deltaY = y - position[1]
    const left = parseInt(xxx.style.left || 0)
    const top = parseInt(xxx.style.top || 0)
    xxx.style.left = left + deltaX + 'px'
    xxx.style.top = top + deltaY + 'px'
    position = [x, y]
  })
  document.addEventListener('mouseup', function(e){
    dragging = false
  })
  </script>
</html>