目录
一、事件委托
1.1 概念
1.2 代码示例
二、tab栏切换案例
一、事件委托
1.1 概念
事件委托是一种在JavaScript中常用的技术,它利用了DOM事件冒泡的原理。事件冒泡是指当在DOM树中较低层次的元素上发生事件时,这个事件会向上冒泡到更高层次的元素,直到文档的根元素。事件委托通过在父元素上设置一个事件监听器来处理所有子元素的事件,无论这些子元素是静态的还是动态添加的。
想象一下,你是一个大型图书馆的管理员,而你的任务是响应读者的请求。图书馆有很多书架(DOM中的子元素),每个书架上都摆满了书籍。读者可能会在任何书架前提出请求,比如需要某本书或者帮助,你有一下两种解决方法:
- 单独响应:如果你为每个书架安排一个工作人员,那么每当有读者提出请求时,相应的工作人员就需要响应。这就像是为DOM中的每个子元素单独绑定事件监听器。这样做的缺点是,如果图书馆有很多书架,你就需要很多工作人员,这不仅成本高,而且难以管理。
- 事件委托:相反,你可以在图书馆的入口处设置一个信息台,并安排一个接待员。这个接待员(事件监听器)会注意到任何读者的请求,并根据请求的来源(哪个书架)来提供帮助。这就像是在父元素(图书馆)上设置一个事件监听器来处理所有子元素(书架)的事件。
1.2 代码示例
在JavaScript中,这个“信息台”对应于DOM中的父元素,比如一个 <ul> 标签,它包含了多个 <li> 子元素。
事件监听器作为接待员:这个“接待员”对应于事件监听器,它被附加到父元素上,而不是每个子元素上。
事件冒泡作为请求信号:当读者(子元素)提出请求(事件)时,这个请求会像事件冒泡一样,从子元素传递到父元素,直到到达信息台(父元素的事件监听器)。
区分请求来源:在事件处理程序中,通过 event.target (事件的实际目标),接待员(事件监听器)可以确定是哪个读者(子元素)发出的请求,从而提供相应的服务。
// 父元素(图书馆)上的事件监听器(接待员)
const library = document.getElementById('library');
library.addEventListener('click', function(e) {
// 检查请求是否来自读者(<li>元素)
if (e.target.tagName === 'LI') {
// 根据请求的来源提供帮助
console.log('Reader at bookshelf ' + e.target.textContent + ' needs assistance.');
}
});
library 是父元素(图书馆), e.target 是实际触发事件的元素(读者所在的书架)。通过在父元素上设置一个事件监听器,我们可以处理所有子元素的事件,就像接待员可以响应所有读者的请求一样。这样,无论何时有新的“书架”( <li> 元素)加入“图书馆”( <ul> 元素),我们都不需要额外的“工作人员”(不需要为每个新元素绑定事件监听器)。这就是事件委托的力量和便利性。
了解了基本的用法后让我们来做一个简单的tab栏切换小案例吧~
二、tab栏切换案例
// 查询页面上class为'tab-nav'的元素内部的ul元素,并将其存储在变量`ul`中。
const ul = document.querySelector('.tab-nav ul');
// 为ul元素添加一个点击事件监听器。
ul.addEventListener('click', function(e){
// 如果被点击的元素(e.target)的tagName是'A',即点击的是<a>标签。
if (e.target.tagName == 'A'){
// 首先,移除当前活跃(active)状态的<a>标签的'active'类。
document.querySelector('.tab-nav .active').classList.remove('active');
// 给被点击的<a>标签添加'active'类,标记为当前活跃状态。
e.target.classList.add('active');
// 获取被点击的<a>标签的data-id属性值,并转换为整数。
const i = +e.target.dataset.id;
// 移除当前活跃状态的tab内容区域的'active'类。
document.querySelector('.tab-content .active').classList.remove('active');
// 根据被点击的<a>标签的data-id属性值,找到对应的tab内容区域,并添加'active'类。
// `.item:nth-child(${i + 1})`是一个CSS选择器,用于选择第i+1个.item元素。
document.querySelector(`.tab-content .item:nth-child(${i + 1})`).classList.add('active');
}
});