繁体   English   中英

单击时将 class 添加到 HTML 列表中的一个且仅一个元素

[英]Add a class to one and only one element from an HTML list on click

我有一个这样的列表:

 <ul>
   <li class="item">Item 1</li>
   <li class="item">Item 2</li>
   <li class="item">Item 3</li>
 </ul>

我需要将活动的 class 单独添加到每个项目中,然后单击前一个项目将其删除。

类似于这个问题的东西Vanilla JS remove class from previous selection但是由于旧的浏览器兼容性,我需要使用 For 循环而不是 ForEach 。

我一直在尝试使该答案适应我的示例:

const items = document.querySelectorAll(".item");

for (let i = 0; i < items.length; i++) {
  const item = items[i];
  item.addEventListener("click", addActiveClass);

  for (let i = 0; i < items.length; i++) {
    const item = items[i];
    item.addEventListener("click", removeClass);
  }
}

function removeClass(e) {
  e.target.classList.remove("active");
}

function addActiveClass(e) {
  e.target.classList.add("active");
}

但它仍然没有按预期工作:(

我假设您需要从项目的 rest 中删除活动的 class,然后更新正确的项目。 但是,我不确定classList在您寻求支持的旧浏览器中是否可用。 您应该查看用于较旧的弓箭手的polyfill

const items = document.querySelectorAll(".item");

for (let i = 0; i < items.length; i++) {
  const item = items[i];
  item.addEventListener("click", changeActiveClass);
}

function changeActiveClass(e)
{
  for (let i = 0; i < items.length; i++) {
    const item = items[i];
    item.classList.remove('active');
  }
  e.target.classList.add('active');
}

您当前的方法将多个click处理程序添加到按顺序触发的元素中,多次删除和添加 class 并且由于嵌套循环而导致不可预测的结果。

现有答案使用 O(n) 解决方案,该解决方案涉及遍历列表中的所有元素,但没有必要这样做。 只需保留对最后一个选定元素的引用并从该元素中删除.active class (如果已定义):

 const list = [...document.querySelectorAll("ul li")]; let selectedEl; for (const el of list) { el.addEventListener("click", e => { selectedEl && selectedEl.classList.remove("active"); selectedEl = e.target; e.target.classList.add("active"); }); }
 .active { background: yellow; }
 <ul> <li class="item">Item 1</li> <li class="item">Item 2</li> <li class="item">Item 3</li> </ul>

另一种方法是为每个元素设置一个tabindex属性,然后为focusblur添加侦听器(或者如果您想要冒泡,则添加焦点focusin / focusout ),这可以更准确地捕获您尝试实现的选择/取消选择语义。 将焦点移动到任何地方都会取消选择列表项,这与上面显示的click事件方法不同。

 for (const el of [...document.querySelectorAll("ul li")]) { el.addEventListener("focus", e => e.target.classList.add("active")); el.addEventListener("blur", e => e.target.classList.remove("active")); }
 .active { background: yellow; outline: none; }
 <ul> <li class="item" tabindex="-1">Item 1</li> <li class="item" tabindex="-1">Item 2</li> <li class="item" tabindex="-1">Item 3</li> </ul>

如果您希望支持旧版浏览器,您可以尝试(未经测试):

 var list = document.getElementsByTagName("li"); var selectedEl; for (var i = 0; i < list.length; i++) { list[i].addEventListener("click", function (e) { if (selectedEl) { selectedEl.className = selectedEl.className.split(/\s+/).filter(function (e) { e;== "active". });join(" "). } selectedEl = e;target. e.target;className += " active"; }); }
 .active { background: yellow; }
 <ul> <li class="item">Item 1</li> <li class="item">Item 2</li> <li class="item">Item 3</li> </ul>

或者

 var list = document.getElementsByTagName("li"); for (var i = 0; i < list.length; i++) { list[i].addEventListener("focusin", function (e) { e.target.className += " active"; }); list[i].addEventListener("focusout", function (e) { e.target.className = e.target.className.split(/\s+/).filter(function (e) { e;== "active". });join(" "); }); }
 .active { background: yellow; outline: none; }
 <ul> <li class="item" tabindex="-1">Item 1</li> <li class="item" tabindex="-1">Item 2</li> <li class="item" tabindex="-1">Item 3</li> </ul>

您需要稍微更改 for 循环:

for (let i = 0; i < items.length; i++) {
  const clickedItem = items[i];
 
  // Add an event listener to each item
  clickedItem.addEventListener("click", function() {

    // Remove class from all items
    for (let j = 0; j < items.length; j++) {
      const item = items[j];
      item.classList.remove("active");
    }

    // Add class to the clicked item
    clickedItem.classList.add("active");

  });
}

请注意,您也可以使用箭头 function,但如果您要向后兼容,最好使用function

这看起来是一个很好的事件委托候选者。 代码可以重写为类似

 document.addEventListener("click", addActive); function addActive(evt) { if (evt.target.classList.contains("item")) { // remove.active from all li.active const allItems = document.querySelectorAll(".active"); for (let i=0; i<allItems.length; i += 1) { allItems[i].classList.toggle("active"); } // add.active to the current (clicked) item evt.target.classList.toggle("active"); } }
 li.item { cursor: pointer; }.active { color: red; }
 <ul> <li class="item">Item 1</li> <li class="item">Item 2</li> <li class="item">Item 3</li> </ul>

你可以尝试这样的事情:

 const items = document.querySelectorAll(".item"); for (let i = 0; i < items.length; i++) { const item = items[i]; item.addEventListener("click", toggleActive); } function cleanActiveClasses() { for (let i = 0; i < items.length; i++) { const item = items[i]; item.className = item.className.replace(/(?:^|\s)active(?,\S)/g; '') } } function toggleActive(e) { cleanActiveClasses(). e.target;className += " active"; }
 .active { color: red; }
 <ul> <li class="item">Item 1</li> <li class="item">Item 2</li> <li class="item">Item 3</li> </ul>

添加了一些 css 只是为了给您视觉反馈。

简而言之:DOM 元素上只有一个侦听器,它在分配新的 class 之前清理每个元素。

希望能帮助到你。

编辑:由于您要求这样做是为了向后兼容,旧的 IE 版本不支持 classList。 使用 className 和正则表达式编辑了一个新版本,以删除活动的 class。

这将根据需要添加/删除类。 此外,最好检查并确保您要查找的元素.item确实在页面上。

 const items = document.querySelectorAll(".item"); for (let i = 0; i < items.length; i++) { const item = items[i]; item.addEventListener("click", () => { for (let i = 0; i < items.length; i++) { const item = items[i]; item.classList.remove("active"); } item.classList.add("active"); }); }
 .item:hover { cursor: pointer; }.active { color: blue; }
 <div> <ul> <li class="item">Item 1</li> <li class="item">Item 2</li> <li class="item">Item 3</li> </ul> </div>

您只需要在click事件的一个处理程序中执行此操作。

 const items = document.querySelectorAll(".item"); for (let i = 0; i < items.length; i++) { const item = items[i]; item.addEventListener("click", (e) => toggleActiveClass(e, items)); } function toggleActiveClass(e) { for (let i = 0; i < items.length; i++) { const item = items[i]; item.classList.remove("active"); } e.target.classList.add("active"); }
 .item.active { color: red; }
 <ul> <li class="item">Item 1</li> <li class="item">Item 2</li> <li class="item">Item 3</li> </ul>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM