当文件输入被取消时,HTML对话框会自动关闭。如何防止这种情况发生?

3
如果在对话框中有一个文件输入,取消文件选择会导致对话框关闭。为什么会发生这种情况,如何防止这种情况发生?

<dialog open>
  <input type="file">
</dialog>

编辑:

在Firefox中,对话框保持打开状态(如预期)。在Chrome中,对话框关闭(不符合预期)。


<input>标签没有</input>这样的东西。把它删掉。 - Rob
3个回答

2
我实际上遇到了完全相同的问题。我怀疑这是由于输入触发了一个“取消”事件,当用户取消文件选择时。这个“取消”事件冒泡到了对话框,它错误地认为这个事件是属于自己的,因此提前关闭了。这个问题似乎只出现在Chromium浏览器中,因为在Firefox中并没有发生这种行为,正如你之前提到的。
当出现这种情况时,对话框的“取消”事件被触发,但事件的目标是输入框。这对于检测对话框是否即将提前关闭,并以布尔变量的形式引发一个标志非常有用。
const dialog = document.getElementById("dialog");
let prematurelyClosed = false;

dialog.addEventListener("cancel", (e) => {
  if(e.target !== dialog)
     prematurelyClosed = true;
  // or simply prematurelyClosed = e.target !== dialog
})

那样,当对话框的“close”事件被调用时,我们可以检查标志是否被提起。如果是的话,我们就知道对话框正在关闭时不应该关闭,并阻止它。然而,似乎唯一的“阻止”方法是根据@underflow的答案,我们需要立即重新打开模态框。我没有找到其他方法。至少通过这种方法,我们只需要在特定情况下重新打开它,并在其他情况下正确关闭它,比如用户按下Esc键或者按钮调用dialog.close()
dialog.addEventListener("close", (e) => {
  if(prematurelyClosed){
    dialog.showModal();
    prematurelyClosed = false;
  }
})

所以最后,我得到了这个解决了我的问题,并希望能帮到你的。

const dialog = document.getElementById("dialog");
let prematurelyClosed = false;

dialog.addEventListener("cancel", (e) => {
  if(e.target !== dialog)
     prematurelyClosed = true;
  // or simply prematurelyClosed = e.target !== dialog
})

dialog.addEventListener("close", (e) => {
  if(prematurelyClosed){
    dialog.show();
    prematurelyClosed = false;
  }
})
<dialog open id="dialog">
  <input type="file">
  <button onclick="dialog.close()">Close</button>
</dialog>


好的解决方法! - Jens Renders
我注意到cancel事件对象的cancelable: false,这可能是为什么在对话框的cancel事件处理程序中调用e.preventDefault()无法阻止其关闭的原因。我猜你也尝试过这个方法。我还尝试了在文件输入上处理cancel事件,并使用preventDefault()stopPropagation(),但是无论我尝试了什么,都无法阻止对话框接收到不可取消的cancel事件并关闭。你对如何实现这一点有进一步的见解吗? - Neek
2
@Neek 抱歉,但是很遗憾我对此没有更深入的了解。我尝试在对话框和输入上取消事件,甚至尝试使用stopImmediatePropagation(),但都没有成功。顺便说一下,这似乎确实是Chromium的一个bug,而且已经有补丁一段时间了。虽然我不知道我们什么时候会在浏览器上看到它,但希望很快。 - Urban
1
@Urban,你真是个明星,我在上周的调查中没有找到那个错误报告。根据你的建议,我下载了Version 117.0.5855.0 (Developer Build) (64-bit)(通过$ npx @puppeteer/browsers install chromium@latest),问题似乎已经解决了。文件输入获得了“cancel”事件,对话框也收到了“cancel”事件,但没有收到“close”事件。根据当前的行为,文件输入和对话框元素接收到的“cancel”事件(不确定是否是同一个事件对象)仍然具有cancelable:false属性。我会等待稳定版本发布,并暂时忽略这个问题。 - Neek

0
我在处理一个Angular应用时遇到了同样的问题。基本上,输入框的取消事件会冒泡到调用组件。我通过在输入组件上使用主机监听器来解决了这个问题,以便监听并阻止事件传播到其他组件。
@HostListener('cancel', ['$event'])
  onCancel(event: Event){ 
    console.log('Cancel host listener.'); 
    event.stopImmediatePropagation(); 
  };

0
找到了一个好办法,在点击取消或按下Esc键后保持对话框/模态框的打开状态。

const dialog = document.getElementById("dialog");

dialog.addEventListener('close', (e) => {
  dialog.showModal();
});

const closeButton = document.querySelector(".close");
closeButton.addEventListener("click", () => {
  dialog.style.display = "none";
});
<dialog id="dialog" open>
  <input type="file" />
  <button class="close">Close</button>
</dialog>

在这种特定情况下,手动关闭模态框的最佳方法是通过CSS。

那你怎么关闭这个对话框呢? - Jens Renders
那你怎么关闭这个对话框呢? - undefined
添加了手动关闭的代码 - underflow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接