DOM 事件机制

252 阅读4分钟
文章主要讲述了:
  • DOM事件级别
  • DOM事件流
  • 事件对象

一、DOM事件级别

通俗来讲,事件是用户或者浏览器自己执行的某种动作,是文档或浏览器发生的一些交互瞬间.DOM级别一共可以分为四个级别:DOM 0级「通常把DOM 1规范形成之前的叫做DOM 0级」、DOM 1级、DOM 2级和DOM 3级.
DOM事件分为三个级别:DOM 0级事件处理,DOM 2级事件处理和DOM 3级事件处理。针对不同级别的DOM,相对应的DOM事件处理方式也是不一样的.
DOM 1级标准没有定义相关的事件内容,所以没有DOM 1级事件.
![](https://pic4.zhimg.com/80/v2-710a1fc077574c154be8a0faee1174be_720w.png)
DOM级别与DOM事件
最早的事件处理方式是HTML事件处理程序,也是最早的事件处理方式,举例如下.
<body>
  <button value="按钮" onclick="clickEvent()"></button>
  <script>
    function clickEvent(){
      alert("HTML事件处理程序")
    }
  </script>
</body>
缺点:HTML和JavaScript代码紧密耦合,如果要更换事件处理程序,HTML代码和JavaScript代码都必须改动;(优点:不需要操作DOM即可完成事件绑定)所以就有了DOM事件.

1.DOM 0级事件处理

DOM 0级事件即在JavaScript代码中指定对象,并为其绑定对应的事件处理程序,规避了HTML事件中HTML代码和JavaScript代码耦合的问题,且可以通过给事件处理属性赋值null来解绑事件:
<body>
  <button value="按钮"></button>

  <script>
    var btn = document.querySelector("button")
    btn.onclick = function (){ alert("DOM 0级事件处理程序")}
  </script>
</body>
缺点:
  • 不能给一个元素同时添加两个事件;
  • 不能控制元素的事件流(捕获或冒泡,后面解释事件流);

2.DOM 2级事件处理

在JavaScript代码中对指定的对象添加事件处理函数(可以是多个),如下:
<body>
  <div id="demo"></div>
  <script>
    //给demo添加了两个事件
    demo.addEventListener("onclick",clickFn,false)//添加鼠标点击事件
    demo.addEventListener("mouseover",showFn,false)//添加鼠标移入事件
    function clickFn(){
      alert('点击了一下')
    }
    function showFn(){
      alert('鼠标移入了')
    }

    //demo.removeEventListener('click',showFn,false) 解绑事件
  </script>
</body>
需要注意的是IE8级以下版本不支持addEventListener和removeEventListener,需要用attachEvent和detachEvent来实现:
demo.attachEvent('onclick', clickFn); // 绑定事件 
demo.detachEvent('onclick', showFn); // 解绑事件 
//ie8以下只支持冒泡型事件,所以不需要传入第三个参数

3.DOM 3级事件

DOM 3级事件在DOM 2级事件的基础上添加了更多的事件类型,全部类型如下:
UI事件,当用户与页面上的元素交互时触发,如:load、scroll
焦点事件,当元素获得或失去焦点时触发,如:blur、focus
鼠标事件,当用户通过鼠标在页面执行操作时触发如:dbclick、mouseup
滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel
文本事件,当在文档中输入文本时触发,如:textInput
键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
合成事件,当为IME(输入法编辑器)输入字符时触发,如:compositionstart
变动事件,当底层DOM结构发生变化时触发,如:DOMsubtreeModified
同时DOM3级事件也允许使用者自定义一些事件。
自定义事件:
<body>
  <div id=div1>
    <button id=button1>点击触发 frank 事件     
    </button>
  </div>
  <script>
    button1.addEventListener('click', ()=>{
        const event = new CustomEvent("liang", {"detail":{name:'honglei', age: 18}})
        button1.dispatchEvent(event)
    })

    button1.addEventListener('liang', ()=>{
      console.log('liang')
    })
  </script>
</body>
以上所有的事件处理函数中的this指向触发事件的那个元素节点.

二、DOM事件流

一个事件发生之后,会在子元素和父元素之间传播,这种传播分成三个阶段.
  • 第一阶段:从window对象传导到目标节点(从外到内),称之为"捕获阶段";
  • 第二阶段: 在目标节点上触发,称之为"目标阶段";
  • 第三阶段: 从目标节点传回window对象(从内到外),称之为"冒泡阶段";
![](https://pic3.zhimg.com/80/v2-95a3955a718cb9a5fb39108e5e61d1a3_720w.png)
我们可以自己选择把函数放在捕获阶段还是冒泡阶段,设置addEventListerner函数的第三个参数为false(默认)走冒泡,设置为true走捕获.
如下示例为冒泡展示:
(点击目标,会以冒泡的形式从内到外依此变色,使用定时器使这个过程更加形象,如果不适用定时器,那么变色几乎使同一时间我们通过肉眼无法看出,但可以在不同目标的点击事件函数上添加console也可以看到变化)
![](https://pic4.zhimg.com/80/v2-085274d57da7938b2051a2250e8ba6b2_720w.png)
代码链接:[http://js.jirengu.com/noquhejega/1/watch](http://js.jirengu.com/noquhejega/1/watch)
需要注意的一点:
捕获和冒泡是发生在父子元素之间的这个传播过程,如果给一个元素绑定事件分别在冒泡和捕获阶段都执行,那么他的执行顺序是怎样的?
demo.addEventListener("click",()=>{
  console.log("冒泡")
})

demo.addEventListener("click",()=>{
  console.log("捕获")
})
![](https://pic3.zhimg.com/80/v2-0df8f5b73cb636554749d913159ad639_720w.png)
demo.addEventListener("click",()=>{
  console.log("捕获")
})
demo.addEventListener("click",()=>{
  console.log("冒泡")
})
![](https://pic3.zhimg.com/80/v2-53bf16864a8b74be7a26414e305eb3ea_720w.png)
如上述代码和图所示,只和监听函数的绑定顺序有关.
有些事件是可以取消冒泡的,有些不可以(mdn搜索事件,可以看到bubbles[该事件是否冒泡]和canceable[该事件是否可以取消冒泡])

三、事件对象

另外: 事件对象参数 e 的e.target(用户点击的,即事件的真正发出者) 和 e.currentTarget(开发者监听的,事件绑定对象)
var a = document.getElementById('A'),
      b = document.getElementById('B');    
function handler (e) {
    console.log(e.target);
    console.log(e.currentTarget);
}
a.addEventListener('click', handler, false);
当点击A时:输出:
<div id="A">...<div>
<div id="A">...<div>
当点击B时:输出:
<div id="B"></div>
<div id="A">...</div>
文章参考:
[JavaScript事件机制 - 掘金](https://juejin.cn/post/6844903982880522254)
[DOM事件机制 - 前端工匠公众号 - SegmentFault 思否](https://segmentfault.com/a/1190000017259386)
[https://wangdoc.com/javascript/events/model.html](https://wangdoc.com/javascript/events/model.html)