DOM事件
DOM事件
- 事件:用户或浏览器自身执行的某种动作。
诸如click(点击)、load(加载)、mouseover(鼠标悬停)。 - 事件处理程序:要在某个事件发生时,调用指定的函数,对事件作出相应的反应

事件模型
D0M级模型(传统模型(Traditional Model)/统注册模型(Traditional Registration Model)
只能注册一个时间处理程序
<!-- HTML --><button>单击我</button>// Script
let handler1 = function () {
console.log('Handler1:', this)
}
let handler2 = function () {
console.log('Handler2', this)
}
document.querySelector('button'). = handler1
document.querySelector('button'). = handler2
//点击button按钮只会输出hander2()函数的结果
DOM Level 2模型:W3C标准事件模型,且不支持低于IE9的浏览器
- 事件捕获阶段(Capturing Phase):-->
- 事件处理阶段(Target Phase)
- 事件冒泡阶段(Bubbling Phase):<--

- Q1:在DOM2模型中如何添加事件
element.addEventListener(event, function, useCapture)
useCapture(添加事件句柄的阶段):
true-->事件句柄在捕获阶段执行
false/空 默认-->事件句柄在冒泡阶段执行
document.querySelector('button').addEventListener('click',handle1,true)
document.querySelector('button').addEventListener('click',handle2,true)
////点击button按钮会同时输出hander1() hander2()函数的结果
- Q2:在DOM2模型中如何移除事件
element.removeEventListener(event, function, useCapture)
useCapture(移除事件句柄的阶段):
true-->事件句柄在捕获阶段被移除
false/空 默认-->事件句柄在冒泡阶段被移除
let btn = document.getElementById('btn');
btn.addEventListener('click', handler, false);btn.removeEventListener('click', handler, false);
-
Q3:target 与currentTarget
div>span{文字},用户点击文字
target: 用户操作的元素,此处就是span
currentTarget: 程序监听的元素,此处就是div
其他:this是e.currentTarget,不推荐使用 -
Q4:如何取消冒泡
e.stopPropagation()
事件特性
- bubbles
- cancelble

事件委托
事件委托就是由祖先元素监听事件,并根据事件来源统一处理。
-
场景一:给100个按钮添加点击事件
A:监听100个的按钮的祖先元素,等冒泡的时候判断target(用户操作的元素)是不是这100个按钮中的元素,是就执行监听事件 -
场景二:监听当年不存在的元素的点击事件
A:监听祖先元素,点击时判断元素是否为目标元素 -
场景三:
<div class="grandpa">
<div class="father">
<div class="child">
<span class="text">文字</span>
</div>
</div>
</div>
对儿子元素(.child)进行 click 事件监听,当该元素被点击时,在控制台输出 我是子元素,我被点击了! 。
- A1
const grandpaEl = document.getElementsByClassName('grandpa')[0];
grandpaEl.addEventListener('click', (e)=>{
const el = e.target;
if(el.className === 'child'){
console.log('我被点击了!');
}
})
//
当点击 .child 元素时会正确输出,
但当点击 .child 里面的 .text 元素时不会正确输出。
根据实际需求,当点击父元素包裹的子元素时,也是相当于点击了父元素,应当触发对应的事件处理函数
因此此种方法严格来说是错误的。
此种方法只适用于被监听的元素没有后代元素时使用。
- A2:递归
const grandpaEl = document.getElementsByClassName('grandpa')[0];
grandpaEl.addEventListener('click', (e) => {
let el = e.target;
while (!el.matches('.child')) {
if (el === grandpaEl) {
el = null;
break;
}
el = el.parentNode;
}
if (el) {
console.log('我被点击了!');
}
})
- A3:事件对象的path属性
const grandpaEl = document.getElementsByClassName('grandpa')[0];
grandpaEl.addEventListener('click', (e)=>{
let child = e.path.find(el => el.matches('.child'));
if(child){
console.log('我被点击了!');
}
})

- 事件委托优点
① 省监听数,省内存
② 可以监听动态元素
封装事件委托
前述场景三A2进行封装
function delegate(agent, eventType, clientSelector, fn){
agent.addEventListener(eventType, (e)=>{
let el = e.target;
while(!el.matches(clientSelector)){
if(el === agent){
el === null;
break;
}
el = el.parentNode;
}
el && fn.call(el, e, el);
})
return agent;
}
部分学习搬运自
https://www.cnblogs.com/lovevin/p/13411994.html
https://www.cnblogs.com/lovevin/p/13122322.html

浙公网安备 33010602011771号