如何通过单击 ::backdrop 来关闭新的 html <dialog> 标签
Posted
技术标签:
【中文标题】如何通过单击 ::backdrop 来关闭新的 html <dialog> 标签【英文标题】:How to close the new html <dialog> tag by clicking on its ::backdrop 【发布时间】:2014-11-09 22:28:49 【问题描述】:我没有找到任何内置的解决方案或解决方法来通过单击其背景 (::backdrop) 来关闭 html5 元素,尽管它显然是一个基本功能。
【问题讨论】:
【参考方案1】:如果您使用click
,即使您从对话框的内部拖动到外部,它也会关闭对话框,这可能很烦人。
您可以使用pointerdown
和pointerup
更准确地检测外部点击。
// Close a dialog when the user clicks outside of it
// Not using click because form submit can trigger click on submit button,
// and also it would close if you drag from within the dialog to the outside
// (e.g. if you're selecting text, or perhaps you start clicking the close button and reconsider)
function clickOutsideToClose(dialog)
function isOutsideDialog(event)
const rect = dialog.getBoundingClientRect();
return (
event.clientX < rect.left ||
event.clientX > rect.right ||
event.clientY < rect.top ||
event.clientY > rect.bottom
);
addEventListener("pointerdown", function (event)
if (event.target !== dialog)
return;
if (isOutsideDialog(event))
addEventListener("pointerup", function (event)
if (isOutsideDialog(event))
closeSettings();
, once: true );
);
到目前为止,我还没有尝试过 div 内容包装方法。也许这也解决了这个问题,或者可以解决这个问题?
【讨论】:
【参考方案2】:@Seralo 答案的简化版本是:
dialog.addEventListener("click", event =>
const rect = dialog.getBoundingClientRect();
if (event.clientY < rect.top || event.clientY > rect.bottom ||
event.clientX < rect.left || event.clientX > rect.right)
dialog.close();
;
【讨论】:
【参考方案3】:另外一个类似于其他人提到的wrapped div方法的简单方法是给对话框本身padding: 0
(比如Chrome倾向于给对话框填充),并在对话框中添加点击事件。 form
元素无论如何都会获得差异,因此不需要额外的 div。
我注意到在上面的任何示例中都没有使用该表单,所以我认为这是值得投入使用的,因为它是在对话框中使用按钮时的标准的一部分。
<dialog style="padding: 0; border: 0;">
<form method="dialog">
<button>Click here</button>
</form>
</dialog>
<script>
function onClick(event)
if (event.target === dialog)
dialog.close();
const dialog = document.querySelector("dialog");
dialog.addEventListener("click", onClick);
dialog.showModal();
</script>
Demo on CodePen
【讨论】:
这将适用于覆盖对话框的任何元素;干得好,包括符合规范的表格。【参考方案4】:我想出了一个非常简单的解决方案来解决这个问题。在<dialog>
中添加一个 div 容器。然后检查这是否是整个事情的父母。如果不是,就是对话框本身,可以关闭。
HTML
<dialog id="favDialog">
<div class="test">
Hello
</div>
</dialog>
JS
document.querySelector('dialog').addEventListener('click', function(e)
if(!e.target.closest('div'))
e.target.close();
);
【讨论】:
这是一个非常好的解决方案,因为它引用了对话框本身,而不是让我编写 ID 150 X 引用的其他代码。【参考方案5】:对于遇到此问题并希望遵循@meaku 推荐的解决方案的任何人,以下是我如何解决它以使用 a 封装元素而不使用 getBoundingClientRect() 计算:
const popup = document.getElementById('popup');
const popupDialog = document.getElementById('popup-dialog');
popup.addEventListener('click', function(e)
console.info(e.target.tagName);
if (e.target.tagName === 'DIALOG') popupDialog.close()
);
<div id="popup" style="padding: 0">
<dialog id="popup-dialog" style="display:none;">
<h4>Dialog Title</h4>
<footer class="modal-footer">
<button id="popup-close" type="button">close</button>
<button id="popup-ok" type="button">ok</button>
</footer>
</dialog>
</div>
【讨论】:
这不是@meaku 推荐的。【参考方案6】:另一个更有效的解决方案是将dialog
-content 包装在带有padding: 0
的div
中。这样,您可以检查单击事件的event.target
,它在背景的情况下引用对话框,在实际模式的情况下引用div
中的任何其他元素。
通过不检查实际尺寸,我们可以防止布局循环。
【讨论】:
【参考方案7】:可以使用对话框边界矩形检测背景点击。
var dialog = document.getElementByTagName('dialog');
dialog.showModal();
dialog.addEventListener('click', function (event)
var rect = dialog.getBoundingClientRect();
var isInDialog=(rect.top <= event.clientY && event.clientY <= rect.top + rect.height
&& rect.left <= event.clientX && event.clientX <= rect.left + rect.width);
if (!isInDialog)
dialog.close();
);
【讨论】:
我还必须检查event.target
是dialog
。例如if (!isInDialog && event.target.tagName === 'DIALOG')
。如果通过点击“enter”在对话框中提交表单,则单击事件事件将从提交按钮冒泡,并且由于某种原因,它的 clientX 和 clientY 为 0。
@kmurph79 在下面试试我的答案 - 它不需要检查边界客户矩形。
有什么理由不用rect.right
和rect.bottom
而不是rect.left + rect.width
和rect.top + rect.height
?以上是关于如何通过单击 ::backdrop 来关闭新的 html <dialog> 标签的主要内容,如果未能解决你的问题,请参考以下文章