PAYATHON 2026

如何用原生 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="关闭弹窗">
  &times;
</button>

按钮可以通过键盘聚焦和激活,比只有点击事件的 <span> 更适合作为关闭控件。

备注:内容仅供参考。