DOM 事件
DOM 事件的级别
HTML 事件处理过程
1
2<input type='button' value='click' onclick="showMsg()"/>
function showMsg(){}DOM0
1
element.onclick=function(){}
DOM2
1
element.addEventListener('click',function(){},false)
第三个参数是冒泡阶段触发
false
(默认)或捕获阶段触发true
DOM3
1
element.addEventListener('click',function(){},false)
在 2 的基础上新增许多事件类型
- UI 事件,当用户与页面上的元素交互时触发,如:load、scroll
- 焦点事件,当元素获得或失去焦点时触发,如:blur、focus
- 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dbclick、mouseup
- 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel
- 文本事件,当在文档中输入文本时触发,如:textInput
- 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
- 合成事件,当为 IME(输入法编辑器)输入字符时触发,如:compositionstart
- 变动事件,当底层 DOM 结构发生变化时触发,如:DOMsubtreeModified
- 同时 DOM3 级事件也允许使用者自定义一些事件。
为什么没有 DOM1 级事件处理呢?因为 1 级 DOM 标准并没有定义事件相关的内容,所以没有所谓的 1 级 DOM 事件模型。
DOM 事件模型
冒泡:首先在最精确的元素上触发,然后向上传播,直到根节点。
捕获:最顶级的元素上触发,传播到最低级的元素上
DOM 事件流
捕获-目标阶段-冒泡到 window 对象
DOM 的结构是一个树形,每当 HTML 元素产生事件时,该事件就会在树的根节点和元素节点之间传播,所有经过的节点都会收到该事件。
三个阶段:
1) 捕获阶段
事件从 window 对象自上向下目标节点传播的阶段
window->document->html->body->…-> 目标元素
2) 目标阶段
真正目标节点正在处理事件的阶段
3) 冒泡阶段
事件从目标节点自下而上向 window 对象传播阶段
跟捕获阶段相反
阻止冒泡
event.stopPropagation()
event.cancelBubble=true
1 | p2.onclick = (e) => { |
DOM 事件捕获的具体流程(事件传播机制)
- window 对象
- document 对象
- html(document.documentElement)
- body
- …
- 目标元素
冒泡过程相反
Event 事件的具体应用
自定义事件
1 | let event = new Event(type,options); |
- type:字符串,事件名
- options:对象,事件配置
- bubbles:布尔值,可选,默认 false,表示事件对象是否冒泡
- cancelable:布尔值,可选,默认 false,表示事件是否可以被取消,即是否能用 Event.preventDefault()取消这个事件。
- “composed”,可选,Boolean 类型,默认值为 false,指示事件是否会在影子 DOM 根节点之外触发侦听器。
1 | //html |
默认 look 事件不能冒泡。div 注册事件时默认冒泡阶段触发(false
),指定在冒泡阶段执行回调函数,然后 p 标签触发事件,div 注册的事件将不会执行,只会输出Tag:P
。
事件对象
属性
- event.bubbles
返回布尔值,表示当前事件是否冒泡,只读 - event.eventPhase
返回整数,表示事件目前所处的阶段,只读- 0,事件目前没有发生
- 1,事件目前处于捕获阶段,即处于祖先节点向目标节点传播的过程
- 2,事件到达目标节点,即 event.target 属性指向的那个节点
- 3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程
- event.cancelable
返回布尔值,表示事件是否可以取消,只读
如果不能取消,调用 event.preventDefault()没有任何效果, - event.cancelBubble
布尔值,默认为 false,如果设为 true,相当于执行 event.stopPropagation(),阻止事件冒泡 - event,defaultPrevented
返回布尔值,默认为 false,如果为 true,表示该事件是否调用过 event.preventDefault() 方法,只读 - event.stopImmediatePropagation()
一个操作同时注册两个事件 a、b,如果在 a 中添加上面操作,b 就不会执行了。 - event.target
触发事件的元素 - event.currentTarget
绑定事件的元素 - event.type
返回一个字符串,表示事件类型,事件的类型是在生成事件的时候指定的。该属性只读。 - event.clientX:鼠标的横坐标
- event.clientY:鼠标的纵坐标
- event.timeStamp
返回毫秒时间戳,表示事件发生的时间,相对于网页加载成功开始计算 - event.isTrusted
返回布尔值,表示事件是否由真实的用户行为产生。比如 click 时间就是用户点击产生的,用 Event 新建的时间则是脚本产生的。 - event.detail
浏览器用户界面事件才具有。返回一个数值,表示事件的某种信息具体含义与事件类型相关。
比如 click 事件,1。单击,2。双击,3。三击
比如鼠标滚轮事件,表示正向滚动的距离,负值就是负向滚动的距离,返回值是 3 的倍数
方法
event.preventDefault()
阻止事件的默认行为。
比如点击链接后,浏览器默认会跳转到另一个页面,使用这个方法以后,就不会跳转了;再比如,按一下空格键,页面向下滚动一段距离,使用这个方法以后也不会滚动了。
该方法生效的前提是,事件对象的 cancelable 属性为 true,如果为 false,调用该方法没有任何效果。- 选择框无法选中。
1
2
3
4
5//html
<input type='checkbox' id='my-checkbox' />
//js
let cb = document.getElementById('my-checkbox');
cb.addEventListener('click', (e) => e.preventDefault())文本输入框设置校验条件,如果输入不符合条件,将无法输入
1
2
3
4
5
6
7
8let input1 = document.getElementById('my-input');
input1.addEventListener('keypress', checkName);
function checkName(e) {
if (e.charCode < 97 || e.charCode > 122) {
e.preventDefault()
}
}
event.stopPropagation()
阻止冒泡,执行后事件不会再向父节点传递event.stopImmediatePropagation()
阻止同一事件的其他监听函数被调用,不管监听函数定义在当前节点还是其他节点。
如果同一个节点对于同一个事件指定了多个监听函数,这些函数会根据添加的顺序依次调用。只要其中有一个监听函数调用了 Event.stopImmediatePropagation 方法,其他的监听函数就不会再执行了event.composePath()
返回一个数组,成员是事件的最底层节点和依次冒泡经过的所有上层节点1
2
3
4
5
6
7
8
9
10
11// HTML 代码如下
// <div>
// <p>Hello</p>
// </div>
var div = document.querySelector('div');
var p = document.querySelector('p');
div.addEventListener('click', function (e) {
console.log(e.composedPath());
}, false);
// [p, div, body, html, document, Window]
添加默认参数
添加自定义数据 CustomEvent
1 | var div = document.querySelector('div'); |
事件代理,事件委托
原理:事件冒泡,将多个子组件的事件冒泡到父组件上
减少代码量,节省内存,减少事件注册,提高性能
动态增加子组件时,不要添加事件