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

Tia*_*usa 8 javascript foreach for-loop

我有一个这样的清单:

 <ul>
   <li class="item">Item 1</li>
   <li class="item">Item 2</li>
   <li class="item">Item 3</li>
 </ul>
Run Code Online (Sandbox Code Playgroud)

我需要将活动类分别添加到每个项目中,并在单击时将其从上一个项目中删除。

类似于这个问题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");
}
Run Code Online (Sandbox Code Playgroud)

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

Mat*_*len 7

我假设您需要从其余项目中删除活动类,然后更新正确的项目。但是,我不确定classList在您寻求支持的旧浏览器中是否可用。你应该考虑的填充工具为老年人bowsers。

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');
}
Run Code Online (Sandbox Code Playgroud)


ggo*_*len 6

您当前的方法click向元素添加多个处理程序,这些处理程序按顺序依次触发,多次删除和添加类,并且由于嵌套循环而产生不可预测的结果。

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

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");
  });
}
Run Code Online (Sandbox Code Playgroud)
.active {
  background: yellow;
}
Run Code Online (Sandbox Code Playgroud)
<ul>
  <li class="item">Item 1</li>
  <li class="item">Item 2</li>
  <li class="item">Item 3</li>
</ul>
Run Code Online (Sandbox Code Playgroud)

另一种方法是为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"));
}
Run Code Online (Sandbox Code Playgroud)
.active {
  background: yellow;
  outline: none;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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

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";
  });
}
Run Code Online (Sandbox Code Playgroud)
.active {
  background: yellow;
}
Run Code Online (Sandbox Code Playgroud)
<ul>
  <li class="item">Item 1</li>
  <li class="item">Item 2</li>
  <li class="item">Item 3</li>
</ul>
Run Code Online (Sandbox Code Playgroud)

或者

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(" ");
  });
}
Run Code Online (Sandbox Code Playgroud)
.active {
  background: yellow;
  outline: none;
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)