事件委托:多层子元素如何定位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'); }
|