[英]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
属性,然后为focus
和blur
添加侦听器(或者如果您想要冒泡,则添加焦点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.