DOM事件机制

194 阅读2分钟

什么是事件

事件是用户在操作浏览器窗口里的内容时,发生的交互瞬间。比如 onclick、onmouseenter、onmouseleave都是事件;

当我们点击一个内容,或者按下某个键;事件也可能是浏览器中发生的事情,比如某个页面加载完成,或者是窗口滚动、浏览器窗口大小被改变。

什么是事件机制

事件机制也叫做事件模型、事件流,意思就是从页面里接受事件的顺序;

主要分为两种:事件捕获和事件冒泡。

举例:

// html:
<div id="yeye"> 
    <div id="baba"> 
      <div id="erzi">
        文字
      </div>
    </div>
  </div>

// 即:爷爷>爸爸>儿子

给三个div分别添加事件监听:fnYe、fnBa、fnEr;

问题1

点击文字,算不算点击儿子?

点击文字,算不算点击爸爸?

点击文字,算不算点击爷爷?

答案:

都算,点文字,既算点击了儿子,也算点击了爸爸和爷爷元素。

问题2

三个元素都有事件监听,那么点击文字的时候,应该先调用哪个函数呢?

答案:

IE5团队认为:应该先调用fnEr,然后调用fnBa,最后是fnYe;

网景团队认为:应该先调用fnYe,然后调用fnBa,最后是fnEr;

最后W3C在2002年发布了标准:DOM Level2 Events Specification,规定了浏览器应该同时支持这两种调用顺序:

首先按 爷爷 → 爸爸 → 儿子 顺序看有没有函数监听;

然后按 儿子 → 爸爸 → 爷爷 顺序看有没有函数监听;

有监听函数就调用,并且提供相应的事件信息,没有就跳过。

捕获和冒泡

像 爷爷 → 爸爸 → 儿子 这种顺序来执行事件的顺序叫 事件捕获

像 儿子 → 爸爸 → 爷爷 这种顺序来执行事件的顺序叫 事件冒泡

从外向内 找监听函数,叫 事件捕获从内向外 找监听函数,叫 事件冒泡

问题3

既然要先捕获,再冒泡,那岂不是fnYe、fnBa、fnEr每个函数都要调用两次?

答案:不是,因为开发者可以自己选择把函数放在捕获阶段还是冒泡阶段,定好放在哪个阶段,另外一个阶段就不会执行了;

如何选择把函数放在哪个阶段执行呢?

通过addEventListener这个API来决定:

baba.addEventListener('click',fnBa,bool)

这里的bool值如果不写,或者写一个falsy值,那么函数fn就会走冒泡的顺序。即浏览器在冒泡阶段发现baba元素有监听函数,就会调用并且提供事件信息。

这里的bool值如果写true,就会走捕获的顺序。即浏览器在捕获阶段发现baba元素有监听函数,就会调用并且提供事件信息。

所以我们可以通过修改addEventListener()里的bool值来决定函数走哪个事件顺序,在哪个阶段被调用;

示意图: