查看原文
其他

【第1180期】迎接新的 Dialog 元素

轻舞飞扬 前端早读课 2019-10-24

前言

自从【第1172期】HTML 5.2 有哪些新内容?推送完之后,应该会有人自寻亮点去写Demo吧。今日早读文章由@轻舞飞扬 翻译授权分享。

@轻舞飞扬,前端技术搬运工

正文从这开始~

HTML 5.2 为原生弹窗对话框引入了一个新的 <dialog> 元素。乍一看,它似乎相当简单(本来就是),但当我和它打交道的过程中,我发现有一些很棒的新特性很容易被忽视掉。

在本文的最后我加上了一个完整可行的 Demo,但是如果你想在阅读的过程中也查看的话,你可以看这里。

这是一个基本的弹窗对话框标记:

<dialog open>
 Native dialog box!
</dialog>

open 属性意味着对话框是可见的。没有它,除非你用 JavaSript 使它出现,否则它就是隐藏的。在添加样式之前,对话框渲染如下所示:

对话框中的文本有加粗的黑色轮廓

它在页面中是绝对定位的,因此它会按照你所期望的那样出现在其他内容前面,并且水平居中。默认情况下,它和内容等宽。

基本操作

JavaScript 有几个方法和属性可以方便地处理 <dialog> 元素。你可能最需要的两个方法是 showModal()  close()

const modal = document.querySelector('dialog');
// 使对话框出现(添加 `open` 属性)
modal
.showModal();
// 隐藏对话框(移除 `open` 属性)
modal
.close();

当你用 showModal() 打开对话框的时候,页面会添加一层背景,阻止用户与对话框之外的内容交互。默认情况下,这层背景是完全透明的,但是你可以改变 CSS 属性使它可见(后面会有更多介绍)。

按 Esc 键会关闭对话框,你也可以提供一个关闭按钮来触发 close() 方法。

还有第三个方法,show() 也会让对话框出现,但不会伴随背景层。用户仍可以和对话框之外的可见的元素进行交互。

浏览器支持和 Polyfill

现在,只有 Chrome 支持 <dialog>。Firefox 提供了默认样式,但是 JavaScript API 仅在标志后启用。我猜想 Firefox 会很快支持它。

上图为 caniuse.com 关于 dialog 特性主流浏览器的兼容情况

庆幸地是,polyfill 提供了 JavaScript 事件和默认样式。用 npm 安装 dialog-polyfill 来使用它 —— 或者使用常用的旧的 <script> 标签。这样 <dialog> 就可以在 IE9及以上版本中使用了。

当使用 polyfill 时,页面上的每个对话框都需要被初始化:

dialogPolyfill.registerDialog(modal);

这不会替代拥有它的浏览器中的原生事件。

样式

打开和关闭对话框完成了,但是它起初看起来并不专业。我们像给其他元素添加样式那样,给对话框添加样式。背景层可以用新的 ::backdrop 伪元素来设计。

dialog {
 padding
: 0;
 border
: 0;
 border
-radius: 0.6rem;
 box
-shadow: 0 0 1em black;
}
dialog
::backdrop {
 
/* make the backdrop a semi-transparent black */
 background
-color: rgba(0, 0, 0, 0.4);
}

对于那些需要使用 polyfill 的老浏览器,这个伪元素选择器将不会起作用,然而,在这个对话框位置后,polyfill 会立即添加一个 .backdrop 元素。你可以像这样用 CSS 来定位它:

dialog + .backdrop {
 background
-color: rgba(0, 0, 0, 0.4);
}

添加更多的标记来提供样式的钩子。一个常用的做法是将对话框划分为标题,正文和页脚:

<dialog id="demo-modal">
 
<h3 class="modal-header">A native modal dialog box</h3>
 
<div class="modal-body">
   
<p>Finally, HTML has a native dialog box element! This is fantastic.</p>
   
<p>And a polyfill makes this usable today.</p>
 
</div>
 
<footer class="modal-footer">
   
<button id="close" type="button">close</button>
 
</footer>
</dialog>

给它添加一些 CSS,你可以让对话框做成任何你想要的外观:

更多控制

通常,我们想要从对话框中获得更多用户反馈。当关闭对话框时,你可以传递一个字符串值到 close() 方法。该值将会被赋值给对话框 DOM 元素的 retrunValue属性,因此它可以在后面被读取到:

modal.close('Accepted');
console
.log(modal.returnValue); // logs `Accepted`

还有一些事件你可以监听。两个有用的事件是 close (当对话框关闭的时候触发)和 cancel(当用户按了 Esc 关闭对话框时触发)。

有一件事似乎被忘掉了,当背景层被点击时能够关闭对话框,但有一个变通方案。当点击背景层时,触发 <dialog> 的点击事件作为事件目标。而且,如果你构造对话框使得子元素填充了整个对话框,那些子元素将会被作为对话框内任何点击的目标。这种方式,你可以监听对话框上的点击,当点击事件的目标是对话框本身的时候关闭它:

modal.addEventListener('click', (event) => {
 
if (event.target === modal) {
   modal
.close('cancelled');
 
}
});

虽然不完美,但是起了作用。如果你找到了更好的方法来检测背景层上的点击,请让我知道。

完整可行的 Demo

我在下面的示例中演示了很多东西。亲自实践下,看你还能用 <dialog> 做些什么。它包含了 polyfill,所以它应该能在大多数浏览器中运行。

Demo:https://codepen.io/keithjgrant/pen/eyMMVL/](https://codepen.io/keithjgrant/pen/eyMMVL/

为你推荐

【第1177期】新的包名规则

【第1170期】如何看待员工跳槽

关于本文

译者:@FateZeros
译文:https://github.com/xitu/gold-miner/blob/master/TODO/meet-the-new-dialog-element.md(掘金翻译)
原文:https://keithjgrant.com/posts/2018/meet-the-new-dialog-element/
作者:@keithjgrant
校对者:@ryouaki、@PCAaron

【图书】你不知道的Javascript(下卷)

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存