DOM 事件级别
DOM 标准 | DOM 事件 |
---|---|
DOM0 | DOM0 |
DOM1 | — |
DOM2 | DOM2 |
DOM3 | DOM3 |
DOM1 标准没有定义事件相关内容,所以不存在 1 级 DOM 事件模型。
内联事件
在 DOM0 之前,事件处理是通过在 HTML 标签内添加 on 事件绑定函数,也是最早的一种事件处理方式;
1 | <button type="button" onclick="show()"></button> |
1 | function show() { |
以上就是直接在 button
标签内直接添加 onclick 属性 onclick="show()"
来触发show()
函数,缺点就是 HTML 和 JS 耦合太强,修改绑定函数名就必须修改两个地方。
DOM0 事件
DOM0 事件通过 js 获取 html 标签元素,将函数赋值给事件属性。
1 | var btn = document.getElementById('btn') |
缺点:无法同时绑定多个处理函数;
解绑可通过给事件属性赋值:btn.onclick = null;
;
DOM2 事件
DOM2 级事件定义了 addEventListener 和 removeEventListener 两个方法,分别用来绑定和解绑事件。
绑定事件:addEventListener
方法中包含三个参数,语法:
target.addEventListener( type, listener[, useCapture] );
target.addEventListener( type, listener[, options] );
- type:
String
,事件类型(click, mousedown…); - listener: 监听事件触发时执行函数;
- useCapture:
Boolean
,可选,默认false
,是否捕获阶段执行,不添加默认冒泡阶段执行。 - opthins:
Object
,可选,第三个参数还可设置成参数对象,可用选项如下:capture
:Boolean
,是否捕获阶段执行;once
:Boolean
,是否只调用一次;passive
:Boolean
,设置为 true 时,表示 listener 永远不会调用preventDefault()
。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。
解绑事件:removeEventListener
同绑定事件一样,⚠️ 注意,解绑时三个参数都要相同才能解绑,尤其是第三个参数,执行阶段不同是不同的 Listener ,所以参数要一致。
1 | var btn = document.getElementById('btn') |
DOM3 事件
DOM3 级事件在 DOM2 级事件的基础上添加了更多的事件类型:
- UI 事件,当用户与页面上的元素交互时触发,如:load、scrol
- 焦点事件,当元素获得或失去焦点时触发,如:blur、focus
- 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dbclick、mouseup
- 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel
- 文本事件,当在文档中输入文本时触发,如:textInput
- 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
- 合成事件,当为 IME(输入法编辑器)输入字符时触发,如:compositionstart
- 变动事件,当底层 DOM 结构发生变化时触发,如:DOMsubtreeModified
同时 DOM3 级事件也允许使用者自定义一些事件。
DOM 事件流
DOM 事件流分三个阶段:捕获阶段 => 目标阶段 => 冒泡阶段
事件捕获
当某事件触发时,会依照 DOM 树从上层依次往下通知 listener,并执行相应监听函数,比如父元素和目标元素都注册了点击事件,且都设置了捕获阶段执行,这时目标元素被点击,则父元素的执行函数会先执行,再来执行目标元素 函数;
事件捕获流程:
window => document => html => body => … => 目标元素
事件冒泡
事件冒泡则与捕获阶段相反,先执行目标元素事件再逐层往上。
阻止捕获、冒泡、默认行为
event.stopPropagation();
: 阻止捕获、冒泡阶段。event.preventDefault();
: 阻止默认行为。event.stopImmediatePropagation()
: 同样可以阻止捕获、冒泡,并阻止相同事件的其它监听函数;
备注:如果有多个相同类型事件的事件监听函数绑定到同一个元素,当该类型的事件触发时,它们会按照被添加的顺序执行。如果其中某个监听函数执行了 event.stopImmediatePropagation()
方法,则当前元素剩下的监听函数将不会被执行。
阻止捕获
1 | window.addEventListener( |
如上,window
和 document
都注册了点击事件,并设置了在捕获阶段执行,正常执行应该是先执行 window 的点击事件再执行 document 的点击事件,在 window 执行后添加了event.stopPropagation();
就直接停止了捕获,所以 document 的点击事件不会被执行。
注意,一般不会这么操作,如上,如果父元素执行完直接停止捕获,连同后续的冒泡阶段都停止,会导致真正被点击的目标元素点击事件不能执行。
阻止冒泡
实际环境中一般绑定事件都只会设置冒泡阶段执行,当遇到父元素和子元素都绑定相同事件时,为避免子元素触发事件时触发父元素事件,才会去阻止冒泡。如下:
1 | parentElement.addEventListener('click', function () { |
阻止默认行为
如<a>
标签或表单提交,点击会跳转链接,有时我们并不需要跳转或暂时不需要跳转,只需要执行相应操作即可,这时就需要阻止默认行为,event.preventDefault();
1 | <form action="test.html"> |
1 | var userName = document.querySelector('#username') |
自定义事件
使用 Event
构造函数创建自定义事件如下:
1 | // 创建自定义事件 |
注意这里的 event 是事件,build 是事件名,绑定和触发并不是用同一个。