如何用原生 JavaScript 点击外部区域或 × 图标关闭弹窗?
给 .modal-close 绑定关闭事件,并在外层 #modal-faqs 的点击事件中判断 event.target === modal。这样点击遮罩会关闭弹窗,点击弹窗内容则不会。
为什么现有代码无法关闭弹窗?
现有代码只在 DOMContentLoaded 时检查 URL hash,并将弹窗的 display 设置为 block,没有处理关闭操作。
× 只会显示一个 × 字符,modal-close 也只是类名,都不会自动提供关闭功能。
替换原有 JavaScript
保留现有 HTML,把原来的 <script> 替换为:
<script>
document.addEventListener('DOMContentLoaded', function () {
const modal = document.getElementById('modal-faqs');
const closeButton = modal.querySelector('.modal-close');
function closeModal() {
modal.style.display = 'none';
// 清除对应的 hash,避免刷新页面后再次自动打开。
if (window.location.hash === '#modal-faqs') {
history.replaceState(
history.state,
'',
window.location.pathname + window.location.search
);
}
}
if (window.location.hash === '#modal-faqs') {
modal.style.display = 'block';
}
closeButton.addEventListener('click', closeModal);
modal.addEventListener('click', function (event) {
if (event.target === modal) {
closeModal();
}
});
});
</script>
点击 .modal-content 或其内部元素时,事件可能冒泡到外层 modal,但 event.target 仍是实际点击的元素。因此,上面的判断可以防止点击标题、正文等内容时误关闭弹窗,无需额外调用 stopPropagation()。
history.replaceState() 用于清除当前弹窗的 hash,不会刷新页面。如果希望关闭后仍保留 #modal-faqs,可以删除 closeModal() 中处理 hash 的 if 代码块;此时刷新页面会再次打开弹窗。
确保外层元素覆盖弹窗之外的区域
原问题没有提供 CSS。上述外部点击处理的前提是,#modal-faqs 充当覆盖页面的遮罩,.modal-content 只占据其中的内容区域。
如果尚未设置这部分样式,可以使用以下基础样式,并按页面需要调整:
#modal-faqs {
display: none;
position: fixed;
inset: 0;
z-index: 1000;
overflow: auto;
background: rgba(0, 0, 0, 0.5);
}
#modal-faqs .modal-content {
box-sizing: border-box;
width: 90%;
max-width: 600px;
margin: 10vh auto;
padding: 24px;
background: #fff;
}
#modal-faqs .modal-close {
cursor: pointer;
}
如果外层元素没有覆盖页面,点击它之外的页面区域就不会触发绑定在它上面的事件。若内容区域占满整个遮罩,也不会留下可点击的外部区域。
顺手修正两个 HTML 细节
原代码中,<section> 和 .modal-content 都使用了 id="faqs"。同一文档中的 id 应保持唯一,可以删除内层 .modal-content 的这个 id。重复 id 不是缺少关闭事件的直接原因,但会影响后续选择元素和锚点定位。
关闭控件也建议改成原生按钮,保留原来的类名即可继续使用上述 JavaScript:
<button type="button" class="modal-close" aria-label="关闭弹窗">
×
</button>
按钮可以通过键盘聚焦和激活,比只有点击事件的 <span> 更适合作为关闭控件。
备注:内容仅供参考。
