背景
做一个动态的导航栏,需要在点击一个导航栏时,将active类转移到我点击的li上,
有多个li,因此想到使用事件委托来实现。
<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元素,不符合我的预期
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');
}
解决方法
第一种
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或者其他属性进行比较,思路与第一种方法相仿,便不再赘述
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');
}