js是浏览器的功能,DOM事件也是浏览器提供的,
js和事件是平行,
js只是调用了DOM提供的addEventListener
,进行事件监听,在用户对网页进行操作时作出一些响应。
除此之外还包括
-
addEventListener
: 绑定事件监听 -
removeEventListener
:移除事件监听 -
dispatchEvent
:触发事件
- 事件冒泡
IE规定,在目标元素触发的事件,由目标元素向上级传播,直到document对象 - 事件捕获
与冒泡相反,由顶级document对象开始向下传播,直到目标对象
完整的DOM事件流由W3C定义有三个阶段:当一个事件发生时,会在子元素和父元素之间进行传播,传播的过程分为可分为三段
- 第一阶段:从Window对象传导到目标节点(上层传到底层),称为“捕获阶段”(capture phase)。
- 第二阶段:在目标节点上触发,称为“目标阶段”(target phase)。
- 第三阶段:从目标节点传导回Window对象(从底层传回上层),称为“冒泡阶段”(bubbling phase)

element.addEventListener(eventype,fn,useCapture)
addEventListener该方法接受三个参数
eventype:事件名称,大小写敏感。
fn:监听函数。事件发生时,会调用该监听函数。
useCapture:布尔值,表示监听函数是否在捕获阶段(capture)触发,默认为false(监听函数只在冒泡阶段被触发)IE模型
举个例子
<div class="grandfather">
<div class="father">
<button class="son"></button>
</div>
</div>
分别在元素.grandfather
、.father
和.son
的捕获阶段和冒泡阶段绑定事件
let grandfather = document.querySelector('.grandfather')
let father = document.querySelector('.father')
let son = document.querySelector('.son')
function f1(e) {
console.log('我点了' + e.target.classList[0])
console.log(e.currentTarget.classList[0] + '事件冒泡阶段,打印')
}
function f2(e) {
console.log('我点了' + e.target.classList[0])
console.log(e.currentTarget.classList[0] + '事件捕获阶段,打印')
}
//冒泡阶段
grandfather.addEventListener('click', f1)
//捕获阶段
grandfather.addEventListener('click', f2, true)
father.addEventListener('click', f1)
father.addEventListener('click', f2, true)
son.addEventListener('click', f1)
son.addEventListener('click', f2, true)

当点击son时,先捕获再冒泡,分别打印了三次
e.target
和e.currentTarget
区别
-
e.target
实际操作的的元素 -
e.currentTarget
事件监听的元素
冒泡可以取消:e.stopPropagation()
取消默认行为e.preventDefault()
:比如a标签可以取消默认的点击跳转
事件委托
利用事件的冒泡机制,将子元素的事件监听绑定到父元素上去,这样当子元素事件触发,事件冒泡到父元素,由父元素去执行相应事件。
事件委托的优点:
- 节省内存消耗,不用给每个子元素绑定事件,给所有子元素的父元素绑定一个事件就好了
- 实现对动态元素的监听
封装事件委托
function on (eventType, element, selector, fn) {
if (!(element instanceof Element)) {//如果不是一个元素 获取DOM对象
element = document.querySelector(element)
}
element.addEventListener(eventType, (e) => {
let el = e.target
while (!el.matches(selector)) {//matches 一个元素是否匹配 选择器
if (element === el) {//如果找到操作元素就是绑定事件的元素结束循环
el = null
break
}
//如果当前操作元素不是绑定事件元素则根据事件委托的机制 继续往上一层寻找绑定元素
el = el.parentNode
}
el && fn.call(el, e, el)
})
return element
}
网友评论