事件委托:多层子元素如何定位target

事件委托:多层子元素如何定位target

背景

做一个动态的导航栏,需要在点击一个导航栏时,将active类转移到我点击的li上,

有多个li,因此想到使用事件委托来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="navigation">
<ul id="nav">
<li class="list active">
<a href="#">
<span class="icon">icon1</span>
<span class="text">1</span>
</a>
</li>
<li class="list">
<a href="#">
<span class="icon">icon2</span>
<span class="text">2</span>
</a>
</li>
</ul>
</div>

问题

初始代码如下,由于li中有a标签,其中又有两个span标签,因此e.target可能是span,也可能是a,也可能是li,不能准确定位到li元素,不符合我的预期

1
2
3
4
5
6
7
8
9
const list = document.querySelectorAll('.list');
const ul = document.getElementById('nav');
ul.addEventListener('click', (e) => activeLink(e));
function activeLink(e) {
list.forEach((item) => {
item.classList.remove('active');
});
e.target.classList.add('active');
}

解决方法

第一种

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const list = document.querySelectorAll('.list');
const ul = document.getElementById('nav');
ul.addEventListener('click', (e) => activeLink(e));
function activeLink(e) {
list.forEach((item) => {item.classList.remove('active');});
let target = e.target;
while (target.tagName.toLowerCase() !== 'ul') {
if (target.tagName.toLowerCase() === 'li') {
break;
} else {
target = target.parentNode;
}
}
target.classList.add('active');
}

第二种

e.path中存储了从当前的target一直到window的所有元素,因此只需要对e.path进行遍历,找到父元素所在的index,那么我的目标元素li就是父元素所在的index-1,同理也可以得到父元素的子元素的子元素,即index-2

当然这里也可以直接对value.tagName或者其他属性进行比较,思路与第一种方法相仿,便不再赘述

1
2
3
4
5
6
7
8
9
10
11
12
const list = document.querySelectorAll('.list');
const ul = document.getElementById('nav');
ul.addEventListener('click', (e) => activeLink(e));
function activeLink(e) {
list.forEach((item) => {item.classList.remove('active');});
let index = 0;
e.path.map((value, _index) => {
if (value === ul) {index = _index;}
});
const target = e.path[index - 1];
target.classList.add('active');
}

事件委托:多层子元素如何定位target
https://bald3r.wang/2022/07/29/32-事件委托:多层子元素如何定位target/
作者
Allen
发布于
2022年7月29日
许可协议