<dialog> 是异步 UI,必须用 Promise 包装 close 事件才能等待用户操作;dialog.returnValue 为字符串需显式判断 'confirmed';不支持时应降级到 confirm()。
<dialog> 元素本身不阻塞 JavaScript 执行,直接调用 showModal() 后代码立刻往下走——这意味着你不能像 confirm() 那样靠“同步返回布尔值”来控制后续逻辑。
dialog 的 close 事件必须配 Promise 才能等用户操作原生 confirm() 是同步阻塞的,而 <dialog> 是异步 UI。不包装 Promise,你就只能把后续动作(比如删除、重置)写在 close 回调里,导致逻辑分散、难以复用、无法 await。
close 事件,并用 { once: true } 确保只响应一次dialog.returnValue 是唯一能拿到用户点击“确定”还是“取消”的地方,但它的值是字符串,不是布尔值returnValue 为空字符串,得显式判断 === 'confirmed',不能只用真值判断showModal() 后立刻读 dialog.returnValue——它此时还是空的showModal() 调用后立即执行后续代码的典型错误常见现象:弹窗刚出来,控制台就打印“执行删除”,实际用户还没点按钮。
dialog.showModal(); console.log('执行删除');
close 事件的 Promise resolve 回调里close——{ once: true } 是底线,否则可能触发多次<dialog>,优先降级方案截至 2026 年 4 月,<dialog> 在旧版 Android WebView 和 IE 中完全不可用;部分 Chromium 内核定制浏览器也存在 returnValue 丢失问题。
立即学习“前端免费学习笔记(深入)”;
typeof HTMLDialogElement !== 'undefined',不通过就 fallback 到 confirm()
showModal() 行为——样式、焦点管理、Esc 键、Backdrop 点击拦截都极难做全confirm() 仍是零依赖最稳选择useState 的 setter 同步等待,仍要走 Promise 链真正容易被忽略的是:无论用 <dialog> 还是自定义 Modal,只要脱离了原生 confirm() 的同步模型,所有调用点就必须适配 Promise ——漏掉一个 await 或没 return Promise,就会导致确认失效。这不是样式问题,是控制流契约。