# Dialog
# 概述
;dialog (opens new window) 是HTML5
新增的语义化双标签,用于展示一个交互式的模态对话框。
绝大多数浏览器都不支持,仅有Chrome
等浏览器支持。
# 属性
# open
用于控制模态框的显隐,即含有open
属性就显示,否则隐藏。
<dialog open>
<p>hello world</p>
</dialog>
浏览器呈现如下,含有部分默认样式,并且仅水平方向居中。
显示时样式。
隐藏时样式。
# returnValue
保留close
方法传入的参数。
# 方法
# show()
显示模态框,对其添加open
属性。
<button>show</button>
<dialog>
<p>hello world</p>
</dialog>
<script>
var btn = document.querySelector('button')
var dialog = document.querySelector('dialog')
btn.addEventListener('click', () => {
dialog.show()
})
</script>
# showModel()
显示模态框,对其添加open
属性并且显示遮罩框,同时监控按键ESC
(按下即关闭)。
<button>showModal</button>
<dialog>
<p>hello world</p>
</dialog>
<script>
var btn = document.querySelector('button')
var dialog = document.querySelector('dialog')
btn.addEventListener('click', () => {
dialog.showModal()
})
</script>
如下单击showModal
显示,按下ESC
关闭。
也可以关闭ESC
的默认行为。
document.onkeydown = ev => {
if (ev.key === 'Escape') {
ev.preventDefault()
}
}
# close()
关闭模态框,删除其open
属性,同时将close
方法参数保留至dialog.returnValue
属性上。
<button class="show">showModal</button>
<button class="returnValue">returnValue</button>
<dialog>
<p>hello world</p>
<button class="close">close</button>
</dialog>
<script>
var showBtn = document.querySelector('.show')
var closeBtn = document.querySelector('.close')
var returnValueBtn = document.querySelector('.returnValue')
var dialog = document.querySelector('dialog')
showBtn.addEventListener('click', () => {
dialog.showModal()
})
closeBtn.addEventListener('click', () => {
dialog.close('hello world')
})
returnValueBtn.addEventListener('click', () => {
console.log(dialog.returnValue)
})
</script>
# 事件
# close
当模态框关闭时触发。
<dialog open>
<p>hello world</p>
<button>close</button>
</dialog>
<script>
var btn = document.querySelector('button')
var dialog = document.querySelector('dialog')
btn.addEventListener('click', () => {
dialog.close()
})
dialog.addEventListener('close', ev => {
console.log('close')
})
</script>
一种比较特殊的情况是,若dialog
元素中包含有form
表单,且form
的method
属性为dialog
,同时form
中含有提交按钮,按钮点击时会关闭模态框并触发close
事件。
<style>
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
}
</style>
<body>
<button>showModal</button>
<dialog>
<form method="dialog">
<div>
<input type="text">用户
</div>
<button type="submit">提交</button>
</form>
</dialog>
<script>
var btn = document.querySelector('button')
var dialog = document.querySelector('dialog')
btn.addEventListener('click', () => {
dialog.showModal()
})
dialog.addEventListener('close', ev => {
console.log('close')
})
</script>
</body>
# cancel
当按下ESC
关闭模态框时触发。
<button>showModal</button>
<dialog>
<p>hello world</p>
</dialog>
<script>
var btn = document.querySelector('button')
var dialog = document.querySelector('dialog')
btn.addEventListener('click', () => {
dialog.showModal()
})
dialog.addEventListener('cancel', ev => {
console.log('cancel')
})
</script>
# 应用场景
# 嵌套模态框
模态框嵌套时,若遮罩背景色均有透明度,视觉效果上会产生叠加。
<style>
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
}
</style>
<button class='outer-btn'>打开外层模态框</button>
<dialog class="outer-dig">
<p>hello world</p>
<button class="outer-close-btn">关闭</button>
<button class="outer-open-btn">打开内层模态框</button>
</dialog>
<dialog class="inner-dig">
<p>hello world</p>
<button class="inner-close-btn">关闭</button>
</dialog>
<script>
var outerBtn = document.querySelector('.outer-btn')
var outerCloseBtn = document.querySelector('.outer-close-btn')
var outerOpenBtn = document.querySelector('.outer-open-btn')
var innerCloseBtn = document.querySelector('.inner-close-btn')
var outerDig = document.querySelector('.outer-dig')
var innerDig = document.querySelector('.inner-dig')
outerBtn.addEventListener('click', () => {
outerDig.showModal()
})
outerOpenBtn.addEventListener('click', () => {
innerDig.showModal()
})
outerCloseBtn.addEventListener('click', () => {
outerDig.close()
})
innerCloseBtn.addEventListener('click', () => {
innerDig.close()
})
</script>
# 点击 modal 关闭 Dialog
参考element ui
的 Dialog (opens new window) 组件,其添加close-on-click-modal
属性后可以通过点击modal
关闭Dialog
。
因此首先需要实现点击modal
关闭Dialog
。
<style>
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
}
</style>
<button>showModal</button>
<dialog>
<p>hello world</p>
</dialog>
<script>
var btn = document.querySelector('button')
var dialog = document.querySelector('dialog')
btn.addEventListener('click', () => {
dialog.showModal()
})
dialog.addEventListener('click', ev => {
console.log(ev.target)
})
</script>
;dialog
默认含1em
的内边距和边框,点击p
标签周围空白区域也会打印dialog
。
因此将dialog
的内边距和边框均去除,在其内部创建div
元素。
dialog {
padding: 0;
border: none;
}
dialog .content {
padding: 1em;
}
<dialog>
<div class="content">
<p>hello world</p>
</div>
</dialog>
然后再根据节点的nodeName
判断是否关闭Dialog
。
dialog.addEventListener('click', function (ev) {
if (ev.target.nodeName === 'DIALOG') this.close()
})
最后考虑添加close-on-click-modal
属性开启此功能,同时封装js
和样式为Dialog
模块。
创建dialog
文件夹,新增index.css
和index.js
,注意不要通过window.onload = function(){}
添加事件,因为引入后外部可能会覆盖掉window.onload
,造成功能失效。
// dialog/index.css
dialog {
padding: 0;
border: none;
}
dialog .content {
padding: 1em;
}
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
}
// dialog/index.js
window.addEventListener('load', () => {
document.querySelectorAll('dialog[close-on-click-modal]').forEach(dialog => {
dialog.addEventListener('click', function (ev) {
if (ev.target.nodeName === 'DIALOG') this.close()
})
})
})
;html
引入dialog
模块。
<head>
<script src="dialog/index.js"></script>
<link rel="stylesheet" href="dialog/index.css">
</head>
<body>
<button>showModal</button>
<dialog close-on-click-modal>
<div class="content">
<p>hello world</p>
</div>
</dialog>
<script>
window.onload = () => {
var btn = document.querySelector('button')
var dialog = document.querySelector('dialog')
btn.addEventListener('click', () => {
dialog.showModal()
})
}
</script>
</body>
# 过渡动画
由于模态框隐藏时display
属性为none
,而transition
是无法对此实现过渡的,因此使用visibility
替代。
dialog:not([open]) {
opacity: 0;
visibility: hidden;
display: block;
}
dialog {
opacity: 1;
transition: opacity 2s ease;
}
# Polyfill
;dialog
浏览器支持程度较低,兼容性方面可以考虑 dialog-polyfill (opens new window)。
注意backdrop
的样式在polyfill
时,要通过dialog+.backdrop
指定样式。
<head>
<link rel="stylesheet" href="node_modules/dialog-polyfill/dialog-polyfill.css">
<style>
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
}
dialog+.backdrop {
background: rgba(0, 0, 0, 0.5);
}
dialog {
padding: 0;
border: none;
}
dialog .content {
padding: 1em;
}
dialog:not([open]) {
opacity: 0;
visibility: hidden;
display: block;
}
dialog {
opacity: 1;
transition: opacity 2s ease;
}
</style>
</head>
<body>
<button>showModal</button>
<dialog>
<div class="content">
<p>hello world</p>
</div>
</dialog>
<script src="node_modules/dialog-polyfill/dist/dialog-polyfill.js"></script>
<script>
var btn = document.querySelector('button')
var dialog = document.querySelector('dialog')
dialogPolyfill.registerDialog(dialog)
btn.addEventListener('click', () => {
dialog.showModal()
})
</script>
</body>
# 🎉 写在最后
🍻伙伴们,如果你已经看到了这里,觉得这篇文章有帮助到你的话不妨点赞👍或 Star (opens new window) ✨支持一下哦!
手动码字,如有错误,欢迎在评论区指正💬~
你的支持就是我更新的最大动力💪~
GitHub (opens new window) / Gitee (opens new window)、GitHub Pages (opens new window)、掘金 (opens new window)、CSDN (opens new window) 同步更新,欢迎关注😉~