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

329 阅读1分钟

背景

做一个动态的导航栏,需要在点击一个导航栏时,将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');
}