1. DOM事件模型
DOM模型用一个逻辑树来表示一个文档,树的每个分支的终点都是一个节点(node),每个节点都包含着对象(objects)。DOM的方法(methods)让你可以用特定方式操作这个树,用这些方法你可以改变文档的结构、样式或者内容。节点可以关联上事件处理器,一旦某一事件被触发了,那些事件处理器就会被执行。
捕获和冒泡:
Netscape认为outer上的处理函数应该先被执行. 这被称作event capturing,即从外到内
IE则认为inner上的处理函数具有执行优先权. 这被叫做event bubbling,即从内到外
于是W3C标准则取其折中方案. W3C事件模型中发生的任何事件, 先(从其祖先元素document)开始一路向下捕获, 直到达到目标元素, 其后再次从目标元素开始冒泡.(先捕获再冒泡,搞清楚这一点很重要)
开发者可以决定事件处理器是注册在捕获或者是冒泡阶段. 如果addEventListener的最后一个参数是true, 那么处理函数将在捕获阶段被触发; 否则(false), 会在冒泡阶段被触发.
也就是每点击一个元素,事件流都会像水泛涟漪一样,只是与涟漪正好相反,dom事件是以点击的元素为中心,先聚拢,再荡漾开去,false和true可以看成是标记,false或者不加参数表示注册在冒泡阶段执行,true表示注册在捕获阶段执行,
示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id="grand1">
爷爷
<div id="parent1">
爸爸
<div id="child1">
儿子
</div>
</div>
</div>
</body>
</html>
grand1.addEventListener('click',function f1(){
console.log('爷爷')
},false)//冒泡
parent1.addEventListener('click',function f1(){
console.log('爸爸')
},true)//捕获
child1.addEventListener('click',function f3(){
console.log('儿子冒泡')
},false)//冒泡
child1.addEventListener('click',function f3(){
console.log('儿子捕获')
},true)//捕获
结果依次为:
- 点击儿子
- 点击爸爸
- 点击爷爷
2. 事件委托
事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素,好处是节省了内存还能够动态监听元素
一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。
示例:
<div id="test">
<div class="red">hi</div>
<div class="red">hi</div>
<div class="red">hi</div>
<div class="red">hi</div>
<div class="red">hi</div>
</div>
delegateEvent(parentSelector, targetSelector, events, fn) {
// 事件处理逻辑,
parentSelector.addEventListener(parentSelector, events, function (e) {
let targetEl = e.target
const currentTarget = e.currentTarget;
// 遍历并判断是否为目标元素,如果不是,则往元素的 parentNode 继续查找
while (!targetEl.matches(targetSelector)) {
// 如果是目标元素则跳出循环
if (targetEl === currentTarget) {
targetEl = null;
break;
}
targetEl = targetEl.parentNode;
}
if (targetEl) {
// 将回调函数的 this 指向目标元素
fn.call(targetEl, Array.prototype.slice.call(arguments));
}
});
}
const test=document.querySelector('#test')
dom.delegateEvent(test,'#test .red','click',()=>{
console.log('我被点击了')
})
最后发现了几篇相当详细的dom和事件委托的文章