JS 事件梳理

Huy大约 3 分钟javascriptjavascript

首先明晰定义,事件是用户和浏览器之间的交互行为,比如鼠标点击、鼠标移动、键盘按下等。

绑定事件不是绑定事件本身而是绑定事件的处理函数。因为这些事件是元素本身就有的能力,只有处理函数是我们后续添加进去的,绑定的是事件的反馈。

事件 ➕ 事件的反馈就是前端交互。

如何绑定事件的处理函数

  1. 直接绑定

    内联事件监听器:

    <button onclick="alert('hello')">点击我</button>
    

    但是这种方法不推荐使用,因为这样就写死了,推荐用句柄方式绑定:

    const oBtn = document.querySelector('button')
    oBtn.onclick = function () {
      alert('hello')
    }
    

    这种方法的优点是兼容性好,但是缺点是只能绑定一个事件,如果有多个事件处理函数,则后面的事件会覆盖前面的事件处理函数。

  2. 事件监听

    // 获取元素
    const btn = document.querySelector('button')
    // 绑定事件
    const clickEvent = function () {
      alert('hello')
    }
    btn.addEventListener('click', clickEvent)
    

    addEventListener是 W3C 规范,优点是可以绑定多个事件处理函数,缺点是兼容性不好,ie9 以下不兼容。

  3. 事件代理

    // 获取元素
    const ul = document.querySelector('ul')
    // 绑定事件
    ul.addEventListener('click', function (e) {
      // 判断点击的元素
      if (e.target.tagName.toLowerCase() === 'li') {
        alert('hello')
      }
    })
    
  4. ie8 及以下的绑定方法: element.attachEvent('onclick', eventHandler)。现在已经淘汰了,不做介绍。

事件流

事件流描述的是从页面中接收事件的顺序。

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

事件捕获:不太具体的节点更早接收到事件,而最具体的节点最后接收到事件。

踩坑点: addEventListener 的第三个参数不为对象时是useCapture 表示是否使用捕获,默认为 false,表示事件冒泡。当为 true 时,为捕获事件。

值得注意的是事件绑定的先后顺序,都是先捕获后冒泡。像洋葱层级一样。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>事件绑定</title>
    <style>
      .wrapper {
        position: relative;
        width: 500px;
        height: 500px;
        background-color: red;
      }
      .outer {
        position: absolute;
        left: 500px;
        width: 300px;
        height: 300px;
        background-color: blue;
      }
      .inner {
        position: absolute;
        left: 300px;
        width: 100px;
        height: 100px;
        background-color: yellow;
      }
    </style>
  </head>
  <body>
    <div class="wrapper">
      <div class="outer">
        <div class="inner"></div>
      </div>
    </div>

    <script>
      // 事件绑定
      // 1. 获取元素
      const wrapper = document.querySelector('.wrapper')
      const outer = document.querySelector('.outer')
      const inner = document.querySelector('.inner')
      const clickEvent = function clickEvent(box) {
        return function () {
          console.log(box + '被点击了')
        }
      }

      // 2. 绑定事件

      wrapper.addEventListener('click', clickEvent('bubble wrapper'), true)
      outer.addEventListener('click', clickEvent('bubble outer'), true)
      inner.addEventListener('click', clickEvent('bubble inner'), true)

      wrapper.addEventListener('click', clickEvent('wrapper'), false)
      outer.addEventListener('click', clickEvent('outer'), false)
      inner.addEventListener('click', clickEvent('inner'), false)
    </script>
  </body>
</html>

如上代码,当点击最小里层黄色方块时,结果为:

wrapper被点击了
outer被点击了
inner被点击了
bubble inner被点击了
bubble outer被点击了
bubble wrapper被点击了

先从外向内捕获,再由内向外冒泡。

Loading...