addEventListener绑定同class元素点击事件仅首次生效原因
问题根本原因
你的代码失效核心原因是对document.querySelector()的行为存在误解:该方法只会返回DOM中第一个匹配选择器规则的元素,不会自动匹配所有符合条件的元素。
你写的document.querySelector('.emoji').addEventListener(...),实际只给页面上第一个带emoji类的元素(也就是初始状态下显示的🙉)绑定了点击事件,第二个emoji元素(🙈)从始至终没有绑定任何点击回调。
代码实际执行流程如下:
- 页面初始加载时,第一个emoji携带
active类,覆盖默认的display: none样式处于可见状态;第二个emoji无active类处于隐藏状态,此时只有可见的第一个emoji能响应点击。 - 第一次点击第一个emoji时,绑定的回调正常执行:两个元素的
active类被切换,第一个emoji失去active类变为隐藏,第二个emoji获得active类变为可见。 - 此时页面上可点击的可见元素是第二个emoji,但你从未给它绑定过点击事件,所以后续所有点击都不会触发回调,表现出来就是代码仅首次点击生效。
你之前开发计算器时遇到的"仅第一个绑定的按钮点击生效"问题,根因完全相同,都是误用querySelector只给第一个匹配元素绑定了事件。
修复方案
你提到的"分别给.open、.closed元素绑定事件"的方案之所以有效,本质就是让两个emoji元素都带上了点击回调,逻辑和下面的方案1一致。
方案1:给所有emoji元素绑定事件
使用document.querySelectorAll()选中所有带emoji类的元素,遍历后逐个绑定事件即可:
// 选中所有.emoji元素,遍历绑定点击事件 document.querySelectorAll('.emoji').forEach(emojiEl => { emojiEl.addEventListener('click', () => { document.querySelector('.open').classList.toggle('active'); document.querySelector('.closed').classList.toggle('active'); }) })
方案2:事件委托(更优写法)
不需要给每个emoji单独绑事件,直接把事件绑定在共同的父容器上,利用事件冒泡机制处理点击即可,后续如果新增同类emoji元素也不需要重复绑定:
// 这里把事件绑在body上,也可以绑在两个emoji的共同父容器上 document.body.addEventListener('click', (e) => { // 判断点击触发源是否是emoji元素,是则执行切换 if (e.target.classList.contains('emoji')) { document.querySelector('.open').classList.toggle('active'); document.querySelector('.closed').classList.toggle('active'); } })
补充说明:你写的CSS逻辑没有问题,问题100%出在JS的元素选择和事件绑定环节。
内容的提问来源于stack exchange,提问作者Wojtek1911
相关产品推荐
相关产品推荐

