如何通过单击其:: backdrop来关闭新的html <dialog>标记

man*_*tra 20 html5 opera dialog google-chrome pseudo-element

我没有找到任何内置的解决方案或解决方法来通过点击它的背景(:: backdrop)来关闭html5元素,尽管它显然是一个基本功能.

mar*_*yzm 29

另一种与其他人提到的包装 div 方法类似的简单方法是提供对话框本身padding: 0(例如,Chrome 倾向于提供对话框填充)并向对话框添加单击事件。无论如何,该form元素都会获取差异,因此不需要额外的 div。我注意到上面的任何示例中都没有使用该表单,因此我认为这是值得添加的,因为它是使用对话框中的按钮时标准的一部分。

function onClick(event) {
  if (event.target === dialog) {
    dialog.close();
  }
}

const dialog = document.querySelector("dialog");
dialog.addEventListener("click", onClick);
dialog.showModal();
Run Code Online (Sandbox Code Playgroud)
form {
  max-width: 200px;
}
Run Code Online (Sandbox Code Playgroud)
<button onclick="window.dialog.showModal()">Open dialog</button>

<dialog id="dialog" style="padding: 0; border: 0;">
  <form method="dialog">
    <div>Hello from dialog element. You can close me by clicking outside or Close button</div>
    <button>Close</button>
  </form>
</dialog>
Run Code Online (Sandbox Code Playgroud)

CodePen 上的演示

  • 一个问题是,例如,当用户在模态中选择某些内容并将光标移到模态之外时。onClick 将在模式之外触发,因为当用户释放鼠标时会触发该事件。 (2认同)

小智 27

可以使用对话框边界矩形检测背景点击.

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();
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 我还必须检查“ event.target”是否是“ dialog”。EG`if(!isInDialog &amp;&amp; event.target.tagName ==='DIALOG')`。如果通过单击“ enter”在对话框内提交表单,则单击事件事件将从“提交”按钮冒泡,并且由于某种原因,其clientX和clientY为0。 (3认同)
  • 感觉它正在做的事情非常复杂。 (3认同)
  • 有什么理由不使用“rect.right”和“rect.bottom”而不是“rect.left + rect.width”和“rect.top + rect.height”? (2认同)

Jan*_*roň 20

::backdrop根据定义,您无法监听对话框上的单击事件:

HTMLDialogElement 接口的 showModal() 方法将对话框显示为模式,位于可能存在的任何其他对话框之上。它与 ::backdrop 伪元素一起显示在顶层。对话框外部的交互被阻止,并且对话框外部的内容呈现惰性。

通过单击外部关闭模式对话框的语义上适当的方法是检查此答案event.target中建议的内容并在此答案中实现,可以简化为

<button onclick="this.nextElementSibling.showModal()">Test</button>

<dialog style="padding: 0" onmousedown="event.target==this && this.close()">
  <form style="padding: 1rem" method="dialog">
    <p>Click outside to close the dialog.</p>
    <button>Click here</button>
  </form>
</dialog>
Run Code Online (Sandbox Code Playgroud)

为了防止通过单击元素内部、按住单击然后在 mouseup 之前退出元素来关闭表单,onmousedown请使用 event 而不是onclick,如 @BritishWerewolf 在评论中建议的那样。

要通过单击外部来检测关闭,请在对话框关闭方法中使用 returnValue 参数并在关闭事件中处理它。-1下面的代码中使用了幻数:

<dialog style="padding: 0"
  onmousedown="event.target==this && this.close(-1)"
  onclose="this.returnValue==-1 && alert('closed by clicking outside')"
>

Run Code Online (Sandbox Code Playgroud)

  • 不过,我确实将 `+1` 更改为 `onclick="event/*...*/"` 改为 `onmousedown` 以防止在元素内部单击,按住单击,然后在 mouseup 之前退出元素。当我试图突出显示文本时,如果鼠标最终位于对话框之外,它就会关闭。 (2认同)

Pot*_*rca 12

最简单的方法(没有计算,没有dialog变量)是直接比较单击的元素是否与对话框相同,使用event.currentTarget

document.querySelector('dialog').addEventListener('mousedown', event => {
    if (event.target === event.currentTarget) {
        event.currentTarget.close()
    }
})
Run Code Online (Sandbox Code Playgroud)

为了避免在对话框边界框内单击也注册,需要设置以下 CSS:

dialog {
    border:0;
    padding:0;
}
Run Code Online (Sandbox Code Playgroud)

您可能会注意到,使用的是onclick,而不是mousedown

这是针对用例(由@BritishWerewolf@Lars Flieger等人提到的),以避免当用户选择文本(即按住“单击”)但最终出现在对话框之外时对话框关闭。


对于多个对话框的作用相同:

document.querySelectorAll('dialog').forEach(element => 
    element.addEventListener('mousedown', 
        event => (event.target === event.currentTarget) && event.currentTarget.close()
    )
)
Run Code Online (Sandbox Code Playgroud)

  • 像魅力一样工作 (2认同)

Jen*_*ell 10

我想出了一个非常简单的解决方案来解决这个问题。在 .div 中添加一个 div 容器<dialog>。然后检查它是否是整个事物的父级。如果没有,那就是对话框本身的问题,可以将其关闭。

超文本标记语言

<dialog id="favDialog">
  <div class="test">
  Hello
  </div>
</dialog>
Run Code Online (Sandbox Code Playgroud)

JS

document.querySelector('dialog').addEventListener('click', function(e) {
  if(!e.target.closest('div')) {
    e.target.close();
  }
});
Run Code Online (Sandbox Code Playgroud)

  • 很好的解决方案。但请注意,当您单击其填充时,对话框也会关闭,即“&lt;dialog&gt;”边框和“&lt;div&gt;”之间的区域(在我的情况下默认为“16px”)。一种修复方法是将“&lt;dialog&gt;”的填充设置为零,并将填充添加到“&lt;div&gt;”。 (3认同)

mea*_*aku 7

另一个更有效的解决方案是将dialog-content包含在divwith中padding: 0.通过这种方式,您可以检查event.targetclick事件,该事件在背景情况下引用对话框div,在实际模态的情况下引用任何其他元素.

通过不检查实际尺寸,我们可以防止布局周期.