JavaScript--事件委托
·
事件流的三个阶段
当一个事件发生时,它会经历三个 phase(阶段):
-
捕获阶段(Capture Phase):从window向下到目标元素
-
目标阶段(Target Phase):到达实际的目标元素
-
冒泡阶段(Bubble Phase):从目标元素向上回到window
捕获阶段: window → document → html → body → parent(父元素) → target(目标)
目标阶段: target
冒泡阶段: target → parent → body → html → document → window
什么是事件委托?
事件委托是一种利用事件冒泡机制,将事件处理程序绑定在父元素上,而不是每个子元素上,通过事件目标(event.target)来判断具体是哪个子元素触发事件的技术。
传统方式 vs 事件委托
传统方式(为每个元素绑定事件)
// 为每个按钮单独绑定事件
const buttons = document.querySelectorAll('.btn');
buttons.forEach(button => {
button.addEventListener('click', function() {
console.log('按钮被点击:', this.textContent);
});
});
// 问题:动态添加的按钮没有事件
const newButton = document.createElement('button');
newButton.className = 'btn';
newButton.textContent = '新按钮';
document.body.appendChild(newButton);
// 这个新按钮没有点击事件!
事件委托方式(在父元素上绑定一个事件)
// 在父元素上绑定一个事件
document.addEventListener('click', function(event) {
// 检查点击的是否是.btn元素
if (event.target.classList.contains('btn')) {
console.log('按钮被点击:', event.target.textContent);
}
});
// 现在动态添加的按钮自动拥有事件
const newButton = document.createElement('button');
newButton.className = 'btn';
newButton.textContent = '新按钮';
document.body.appendChild(newButton);
// 这个新按钮自动拥有点击事件!
事件委托的语法
基本模式
parentElement.addEventListener('click', function(event) {
if (event.target.matches(selector)) {
// 处理事件
}
});
事件委托的原理
事件委托利用的是事件冒泡机制:当子元素发生事件时,这个事件会向上"冒泡"到所有祖先元素。我们可以在父元素上监听事件,然后通过判断 event.target 来知道具体是哪个子元素触发的事件。
比如所学生的作业都交到老师那,然后老师批改作业根据作业的名字来判断是哪个学生的作业。
传统方式(效率低)
// 就像:每个学生单独找老师交作业
const 学生们 = document.querySelectorAll('.学生');
学生们.forEach(学生 => {
学生.addEventListener('click', function() {
console.log(`批改${this.dataset.名字}的作业`);
// 需要为每个学生单独设置
});
});
// 新学生来了,要单独处理
const 新学生 = document.createElement('div');
新学生.className = '学生';
新学生.dataset.名字 = '新同学';
新学生.textContent = '新同学的作业';
新学生.addEventListener('click', 处理作业); // 额外工作
事件委托(效率高)
// 就像:老师设立一个作业收集箱
const 班级 = document.querySelector('.班级');
班级.addEventListener('click', function(事件) {
// 检查交作业的是不是学生
if (事件.target.classList.contains('学生')) {
// 查看作业上的名字
const 学生名字 = 事件.target.dataset.名字;
console.log(`批改${学生名字}的作业`);
}
});
// 新学生来了,直接交作业就行
const 新学生 = document.createElement('div');
新学生.className = '学生';
新学生.dataset.名字 = '新同学';
新学生.textContent = '新同学的作业';
班级.appendChild(新学生);
// 自动就能被处理,不需要额外设置!
-
传统方式
只在页面现有元素上一次性绑定监听器。
后面通过innerHTML、appendChild、Ajax等方式新增的元素当时并不存在,自然没有被绑定,所以需要再手动绑一次。 -
事件委托
把监听器绑在父级(或更高祖先)上,而父级一开始就存在。
无论子元素是页面初始化时还是后来动态添加的,只要事件最终能冒泡到父级,父级就能统一捕获并处理,因此不需要再针对新元素单独处理。
更多推荐


所有评论(0)