
在 EJS 中直接对 document.getElementsByTagName('li') 调用 addEventListener 会报错,因为该方法返回的是 HTMLCollection(类数组对象),而非单个元素;需遍历后为每个元素单独绑定事件。
在 ejs 中直接对 `document.getelementsbytagname('li')` 调用 `addeventlistener` 会报错,因为该方法返回的是 htmlcollection(类数组对象),而非单个元素;需遍历后为每个元素单独绑定事件。
在你的 EJS 模板中,
✅ 正确做法是先获取所有
<script type="text/javascript">
// 获取所有 li 元素(返回 HTMLCollection)
const listItems = document.getElementsByTagName('li');
// 方法一:传统 for 循环(兼容性最好)
for (let i = 0; i < listItems.length; i++) {
listItems[i].addEventListener('click', check);
}
// 方法二:转为数组后使用 forEach(更现代,需注意 IE 不支持)
// Array.from(listItems).forEach(item => item.addEventListener('click', check));
function check() {
console.log(2); // 现在将正确输出 2
}
</script>
⚠️ 重要注意事项:
- 执行时机关键:确保该 <script> 标签位于所有 <li> 元素<strong>之后(你当前的写法满足这一点),否则 getElementsByTagName 可能返回空集合。 </script>
- 避免重复绑定:若页面后续通过 JS 动态添加新
- (如 AJAX 提交后追加任务),上述代码不会自动覆盖新增元素——此时推荐使用事件委托(推荐方案):
<script type="text/javascript">
// ✅ 更优解:事件委托(只需绑定一次,自动响应未来新增的 li)
document.querySelector('.item ul').addEventListener('click', function(e) {
if (e.target && e.target.tagName === 'LI') {
console.log(2);
// 可在此添加勾选样式、数据更新等逻辑
e.target.classList.toggle('completed'); // 示例:切换完成状态
}
});
</script>
? 总结:不要对 getElementsByTagName、getElementsByClassName 等返回集合的方法直接调用 addEventListener;优先考虑事件委托(尤其适用于动态内容),既简洁又高效,还能规避 DOM 加载顺序与重复绑定风险。










