313 字
2 分钟
原生 dialog 元素:模态框的正确打开方式
上周拆掉项目里一个 300 行的手写模态框组件,换成原生 <dialog> 元素,组件文件从 300 行缩到 40 行。这东西值得单独记一篇。
为什么它更好
手写模态框绕不开三个坑:焦点会跑到页面背后、Esc 关不掉、z-index 层层加码还是被浮层盖住。<dialog> 把三个问题全部内建解决:
showModal()打开后焦点圈定在对话框内,Tab 键出不去- Esc 自动触发 close 事件
- 渲染在 top layer,永远盖在普通层叠上下文之上,不用管 z-index
基本用法
<dialog id="confirm"> <p>确认删除这条记录?</p> <form method="dialog"> <button value="cancel">取消</button> <button value="ok">删除</button> </form></dialog>const dlg = document.querySelector('#confirm');dlg.showModal();dlg.addEventListener('close', () => { if (dlg.returnValue === 'ok') doDelete();});form method="dialog" 会自动关闭对话框并把按钮的 value 塞进 returnValue,连事件监听都省了。
样式
遮罩用 ::backdrop 伪元素:
dialog::backdrop { background: rgb(0 0 0 / 40%); backdrop-filter: blur(2px);}打开时有默认的居中定位,可以用 margin: auto 微调。出场动画建议用 transition 配合 allow-discrete,比 JS 控制 class 干净得多。
唯一要注意的:show() 和 showModal() 是两种东西,前者是普通 inline 弹层,没有遮罩也不圈定焦点,别调混了。
原生 dialog 元素:模态框的正确打开方式
https://oliver6868686.tech/posts/dialog-element/