使用原生JavaScript实现模态框关闭时移除body的has-modal-open类
问题根源
- 你写的
body.classList.remove('has-modal-open')放在了关闭按钮的for循环体中,只会在页面初始化的时候执行一次,点击关闭按钮时根本不会触发该逻辑 - 按ESC关闭、点击模态框遮罩关闭的两个场景,也没有添加移除body类的逻辑
- 额外隐藏问题:当前代码会给每个模态框都绑定独立的ESC监听事件,按一次ESC会触发多次回调;点击模态框内部内容也会误触发关闭逻辑
修复后的完整JS代码
const modal = document.querySelectorAll('.modal'); const modalOpenButtons = document.querySelectorAll('[data-open-modal]'); const modalCloseButtons = document.querySelectorAll('[data-close-modal]'); const body = document.querySelector('body'); // 打开模态框逻辑 for (let i = 0; i < modalOpenButtons.length; i++) { const modalOpenButton = modalOpenButtons[i]; modalOpenButton.addEventListener('click', e => { body.classList.add('has-modal-open'); const modalDataAttribute = e.target.getAttribute('data-open-modal'); document.querySelector(`.modal[data-open-modal="${modalDataAttribute}"]`).classList.add('modal--is-open'); }); } // 关闭按钮逻辑 for (let i = 0; i < modalCloseButtons.length; i++) { const modalCloseButton = modalCloseButtons[i]; modalCloseButton.addEventListener('click', e => { e.target.closest('.modal').classList.remove('modal--is-open'); body.classList.remove('has-modal-open'); }); } // 全局ESC监听,仅绑定一次避免冗余 document.addEventListener('keydown', e => { if (e.keyCode === 27) { const openModal = document.querySelector('.modal.modal--is-open'); if (openModal) { openModal.classList.remove('modal--is-open'); body.classList.remove('has-modal-open'); } } }) // 遮罩点击关闭逻辑 for (let i = 0; i < modal.length; i++) { const currentModal = modal[i]; currentModal.addEventListener('click', e => { // 仅点击外层遮罩才触发关闭,避免点击内容区误关 if (e.target === currentModal) { currentModal.classList.remove('modal--is-open'); body.classList.remove('has-modal-open'); } }) }
修改说明
- 把移除
has-modal-open类的逻辑同步添加到了所有关闭模态框的触发场景回调中,确保任意方式关闭模态框都能恢复页面滚动 - 把ESC监听移到全局只绑定一次,减少冗余事件绑定
- 增加遮罩点击判断,避免点击模态框内部内容误触发关闭
- 字符串拼接改用模板字符串写法,可读性更高
内容的提问来源于stack exchange,提问作者Nesta
相关产品推荐
相关产品推荐

