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