在项目开发中经常会有许多 DOM 事件操作,对键盘敲击事件,鼠标点击事件,因此浏览器中的 DOM 事件的触发机制需要了解
DOM 级别一共分为 DOM 0 级,DOM 1 级,DOM 2 级,DOM 3 级,4 个级别
但是由于 DOM 1 级中没有 DOM 事件
因此DOM 事件分为3种级别
DOM 0级(非 W3C 标准)
分为两种
- 在 HTML 标签中定义的事件
- element.on事件名 = function() { }
// <div onclick="test(this)"></div>
function test(e) {
console.log(this)
}
// 或者
element.onclick = function() {}
复制代码
DOM 0 级事件有 2 种方法进行绑定,但只能绑定单个事件,该事件在目标阶段执行
DOM 1级事件
DOM级别1于1998年10月1日成为W3C标准。1 级DOM标准中并没有定义事件相关的内容,所以没有 1 级DOM事件模型。
DOM 2级事件
DOM 2 级事件弥补了不能多事件绑定的缺点,多个事件按照绑定先后顺序触发
element.addEventListener(EventName, callBack, useCapture)
// userCapture 默认为 false,在冒泡阶段监听事件,设为 true 可在捕获阶段监听事件
// 一般用 false,为了兼容 IE
element.removeEventListener(EventName, callback, false) // 移除事件
// IE9 之前
element.attachEvent()
element.detachEvent()
复制代码
useCapture 其他可设置属性
capture: 是否在捕获阶段触发监听 默认 false,一般使用默认,为了兼容 IE
once: 设为 true
则监听函数是否触发一次
passive: 设为 true
则监听函数中不能调用 e.preventDefault()
方法,否则输出警告
element.addEventListener('click', function() {
console.log('welcome')
}, { once: true }) // 只会在第一次点击时打印 welcome
复制代码
DOM 3级事件
包括以下:
- UI 事件 load, scoll
- 焦点事件 blur, focus
- 鼠标事件 mousedown, mouseup
- 滑轮事件 mousewheel
- 文本事件 textInput
- 键盘事件 keydown
- 触摸事件 touch
- 拖拽事件 dragstart, dragend, dragover, dragenter, dragleave, drop
- 合成事件 compositionstart
- 变动事件 DOMsubtreeModified
DOM 事件模型
DOM 事件在触发后经历 3 个阶段,分别为:
-
捕获(capture)阶段,事件从 window 对象传播到目标阶段
当用
addEventListener
监听事件时的最后一个参数为true
时可以在捕获阶段触发事件 -
目标(target)阶段,目标节点处理事件
用 DOM 0 级事件的函数在此时执行
-
冒泡(bubble)阶段,事件从目标节点传播到 window 对象
addEventListener
事件默认在此阶段触发<div id="box"> <a id="sub">事件冒泡</a> </div> <script> const box = document.getElementById('box'), const sub = document.getElementById('sub') box.addEventListener('click', function() { console.log('捕获阶段触发.box') }, true); sub.addEventListener('click', function() { console.log('捕获阶段触发.sub') }, true); sub.onClick = function() { console.log('目标阶段触发') } sub.addEventListener('click', function() { console.log('事件冒泡触发.sub') }, false); box.addEventListener('click', function() { console.log('事件冒泡触发.box') }, false); const event = new Event('click') sub.dispatchEvent(event) // 触发点击事件 </script> // 捕获阶段触发.box // 捕获阶段触发.sub // 目标表阶段触发 // 事件冒泡触发.sub // 事件冒泡触发.box 复制代码
DOM 实现事件委托
为什么使用事件委托?
- 当有大量相同子节点触发同一个事件,可在冒泡阶段动态监听事件,防止创建过多函数,占用过多内存
- 对子节点删除时,不用考虑其他,降低耦合
- 绑定更少元素,降低操作 DOM 次数
<ul>
<li></li>
<li></li>
<li></li>
......
<li></li>
</ul>
<script>
document.querySelector('ul').addEventListener('click', function(e) {
console..log('click is:' + e.target.value)
let value = e.target.value
switch value {
case 0:
...
return ;
case 1:
...
return ;
......
}
})
</script>
复制代码
event 常用对象
-
event.preventDefault()
阻止默认事件触发,比如
<a>
的跳转,表单的提交按钮// <a href="https://www.google.cn">link</a> a.onclick = function() { return false } a.onclick = function(e) { e = e || window.event e.preventDefault(); } <a href="javascript:;"></a> // 该方法一样可以阻止 <a> 默认事件触发 复制代码
-
event.stopPropagation()
阻止事件冒泡
<div id="box"> <a id="sub">事件冒泡</a> </div> <script> const box = document.getElementById('box'), const sub = document.getElementById('sub') sub.addEventListener('click', function(event) { console.log('111') e.stopPropagation() }, false); sub.addEventListener('click', function(event) { console.log('222') }, false); box.addEventListener('click', function(event) { console.log('父类上的监听事件') }, false); </script> // 111 // 222 复制代码
-
event.stopImmediatePropagation()
立即阻止事件冒泡,也阻止同级的其他监听
<div id="box"> <a id="sub">事件冒泡</a> </div> <script> const box = document.getElementById('box'), const sub = document.getElementById('child') sub.addEventListener('click', function(event) { console.log('111') e.stopImmediatePropagation() }, false); sub.addEventListener('click', function(event) { console.log('222') }, false); box.addEventListener('click', function(event) { console.log('父类上的监听事件') }, false); </script> // 111 复制代码
-
e.target
事件触发的元素(真正的事件发出者)
-
e.currentTarget
事件绑定的元素(事件监听者)
element.dispatchEvent(event)
手动触发事件
el.addEventListener('click', function() {
console.log('dispatch 触发')
}, false)
let event = new Event('click')
el.dispatchEvent(event)
// dispatch 触发
复制代码