JavaScript实现全部标记已读时,循环删除按钮仅生效一个的问题
问题分析与解决
你遇到的问题核心在于document.getElementsByClassName()返回的是动态HTMLCollection——当你删除集合内的元素时,这个集合会实时缩短。举个例子:假设初始有3个按钮,i=0时删掉第一个,集合长度立刻变成2,i递增到1后,buttons[1]对应的是原来的第三个按钮,循环结束后第二个按钮就被跳过了,最终只能删掉部分元素。
解决方案
方法1:转成静态数组循环
把动态的HTMLCollection转为普通数组,循环时操作的是静态副本,不受DOM变化影响:
let markAllAsRead = () => { // 转成静态数组 let buttons = Array.from(document.getElementsByClassName("markAsRead")); let notifications = Array.from(document.getElementsByClassName("notification")); let newValue = Number(counter.innerText) - 7; newValue = Math.max(newValue, 0); // 替代if判断更简洁 counter.innerText = newValue; notifications.forEach(notification => { notification.classList.remove("new"); }); buttons.forEach(button => { button.remove(); // remove方法无需传参,直接调用即可 }); };
方法2:倒序循环
从最后一个元素开始处理,前面的元素删除不会打乱当前循环的索引:
let markAllAsRead = () => { let buttons = document.getElementsByClassName("markAsRead"); let notifications = document.getElementsByClassName("notification"); let newValue = Number(counter.innerText) - 7; newValue = Math.max(newValue, 0); counter.innerText = newValue; // 倒序移除notifications的new类(避免同样的动态集合问题) for (let i = notifications.length - 1; i >= 0; i--) { notifications[i].classList.remove("new"); } // 倒序删除按钮 for (let i = buttons.length - 1; i >= 0; i--) { buttons[i].remove(); } };
方法3:用querySelectorAll获取静态NodeList
querySelectorAll()返回的是静态NodeList,不会随DOM变化自动更新:
let markAllAsRead = () => { let buttons = document.querySelectorAll(".markAsRead"); let notifications = document.querySelectorAll(".notification"); let newValue = Number(counter.innerText) - 7; newValue = Math.max(newValue, 0); counter.innerText = newValue; notifications.forEach(notification => { notification.classList.remove("new"); }); buttons.forEach(button => { button.remove(); }); };
另外补充:element.remove()方法不需要传入参数,直接调用就能删除元素本身,之前的buttons[i].remove(buttons[i])是冗余写法。
内容的提问来源于stack exchange,提问作者Allan Bruno
相关产品推荐
相关产品推荐

