【发布时间】:2014-11-09 22:28:49
【问题描述】:
我没有找到任何内置的解决方案或解决方法来通过单击其背景 (::backdrop) 来关闭 html5 元素,尽管它显然是一个基本功能。
【问题讨论】:
标签: html google-chrome dialog opera pseudo-element
我没有找到任何内置的解决方案或解决方法来通过单击其背景 (::backdrop) 来关闭 html5 元素,尽管它显然是一个基本功能。
【问题讨论】:
标签: html google-chrome dialog opera pseudo-element
如果您使用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 内容包装方法。也许这也解决了这个问题,或者可以解决这个问题?
【讨论】:
@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();
}
};
【讨论】:
另外一个类似于其他人提到的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>
【讨论】:
我想出了一个非常简单的解决方案来解决这个问题。在<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();
}
});
【讨论】:
对于遇到此问题并希望遵循@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>
【讨论】:
另一个更有效的解决方案是将dialog-content 包装在带有padding: 0 的div 中。这样,您可以检查单击事件的event.target,它在背景的情况下引用对话框,在实际模式的情况下引用div 中的任何其他元素。
通过不检查实际尺寸,我们可以防止布局循环。
【讨论】:
可以使用对话框边界矩形检测背景点击。
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。
rect.right 和rect.bottom 而不是rect.left + rect.width 和rect.top + rect.height?