JS事件传播和事件模型
事件代理
<ul id="emoji">
<li id="smile">😀</li>
<li>😁</li>
<li>😂</li>
<li>🤣</li>
<li>😃</li>
<li>😄</li>
</ul>
<script>
emoji.onclick = function (e) {
console.log(e.target.innerHTML)
}
</script>
IE 中的事件流
这里要介绍一下 IE 6-8 中的事件流,IE 6-8 中的事件流和标准的 DOM 事件流有(独)所(领)不(风)同(骚),IE 的事件流只支持事件冒泡,不支持事件捕获。
IE 9 之前,它也不支持 addEventListener,也就不能使用其第三个参数来表示是冒泡还是捕获,它提供了非标准的事件侦听器 attachEvent() 方法。
在这个模型中,事件对象使用 event.srcElement 属性,而不是 event.target,但两者的效果相同。
emoji.attachEvent('onclick', function (e) {
var target = e.target || e.srcElement
console.log(target.innerHTML)
})
什么是事件捕获?
事件捕获也是事件传播的一种,其中事件首先被最外层的元素捕获,然后在同一嵌套层次结构中依次触发目标元素的后代(子元素),直到到达最里面的 DOM 元素。
当一个事件发生以后,它会在不同的 DOM 节点之间传播(propagation)。DOM 事件标准描述了事件传播的 3 个阶段:
- 捕获阶段(capture phase) :事件从
Window对象向下传递到目标元素。 - 目标阶段(target phase) :事件到达目标元素。
- 冒泡阶段(bubbling phase) :事件从目标元素上开始冒泡。
在捕获阶段中,事件从祖先元素向下传播到目标元素。当事件达到目标元素后,冒泡才开始。
同时,这三个阶段的传播模型,会使得一个事件在多个节点上触发。
因为浏览器默认是从事件冒泡开始,我们看不到事件捕获,所以想要测试事件捕获,我们需要使用到 addEventListener 方法,addEventListener 用于添加事件句柄、注册监听器,参数三还可以指定在捕获阶段还是冒泡阶段触发事件:
false(默认值)—— 在冒泡阶段开始触发事件;
true—— 在捕获阶段开始触发事件。
smile.addEventListener('click', function(e) {
console.log(e.target.innerHTML)
})
emoji.addEventListener('click', function(e) {
alert('Emoji List')
}, true)
document.addEventListener('click', function () {
alert('document')
})
window.addEventListener('click', function () {
alert('window')
})
// 点击 smile 时,将依次输出 'Emoji List' -> 😀 -> 'document' -> 'window'
// 由于将 list 设置为捕获阶段开始,所以先触发,在触发 😀,然后在依次往上触发。
阻止事件传播
使用 event.stopPropagation() 方法用于阻止捕获和冒泡阶段中当前事件在 DOM 中的进一步传播。
function handler(e) {
e.stopPropagation()
}
复制代码
取消默认事件
使用 event.preventDefault() 方法取消浏览器对当前事件的默认行为,例如:
- 表单元素中使用,它将阻止其提交
- 锚元素中使用,它将阻止其导航
- 上下文菜单中使用,它将阻止其显示或隐藏
function handler(e) {
e.preventDefault()
}
return false 用法涉及哪些步骤
事件处理程序中的 return false 语句执行以下步骤:
- 首先,它停止了浏览器的默认操作或行为。
- 它防止事件传播 DOM(原生JS不生效,jquery生效)
- 停止回调执行,并在调用时立即返回。