Web前端技术 · 第4课19 / 21 | 编码:L04-90
进阶观察 · 从本课知识向前一步

一个按钮,打开原生对话框

打开活动确认框,试着直接确认、填写昵称后确认,再用取消按钮关闭。

先看效果

单独打开演示

01 · 按钮声明操作

<button commandfor="confirm" command="show-modal">打开</button>

commandfor 指向目标 id;command 指明打开模态对话框。声明式命令较新,演示对旧实现保留 showModal() 后备路径。

02 · 表单也能用于关闭

<form method="dialog">…</form>

这里不会发送 HTTP 报名请求。通过校验后关闭对话框,并记录所按按钮的 value。

03 · 取消不应被必填阻挡

<button value="cancel" formnovalidate>取消</button>

formnovalidate 让这个提交按钮跳过约束检查;确认按钮仍检查 required。

思考

输入合法昵称后点击确认,对话框关闭了。这能证明服务器已经收到报名吗?为什么取消按钮要与确认按钮区别处理?

展开参考分析

不能。method="dialog" 只完成对话框内部交互,不向服务器提交数据。取消表示退出输入,不应要求先满足必填;确认才需要当前规则的校验。

前沿 HTML:Invoker Commands 声明式命令。先检测支持,基础 dialog 和后备脚本确保演示可操作。

完整源码:展开、修改与运行
<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>一个按钮,打开原生对话框</title>
  <style>
body { margin:16px; color:#183347; background:white; font:20px/1.5 "Times New Roman",SimSun,serif; }
h1,h2 { font-family:"Times New Roman",SimHei,sans-serif; }
button,input,select { font:inherit; max-width:100%; }
button { margin:4px 0; cursor:pointer; }
pre { white-space:pre-wrap; overflow-wrap:anywhere; font:18px/1.5 Consolas,SimSun,monospace; }
:focus-visible { outline:3px solid #b56220; outline-offset:3px; }
dialog { border:2px solid teal; max-width:80%; }
dialog::backdrop { background:rgb(0 0 0 / 35%); }
  </style>
</head>
<body>
<button id="open" commandfor="confirm" command="show-modal" type="button">打开活动确认框</button>
<dialog id="confirm" aria-labelledby="dialog-title">
<h2 id="dialog-title">确认活动选择</h2>
<form method="dialog">
<label>昵称 <input name="nickname" required>
</label>
<p>
<button value="confirm">确认</button> <button value="cancel" formnovalidate>取消</button>
</p>
</form>
</dialog>
<p id="state" role="status">尚未选择</p>
  <script>
const opener = document.querySelector('#open');
const dialog = document.querySelector('#confirm');
if (!('commandForElement' in opener)) {
  opener.addEventListener('click', () => dialog.showModal());
}
dialog.addEventListener('cancel', () => { dialog.returnValue = 'cancel'; });
dialog.addEventListener('close', () => {
  document.querySelector('#state').textContent = '关闭结果:' + dialog.returnValue;
});
  </script>
</body>
</html>