了解新标签----<dialog>

原文出处 Meet the New Dialog Element

HTML 5.2中引入了本地模式对话框标签<dialog>,乍一看,这个标签相当容易理解,当然它的确如此。但是在使用的过程中,我发现它有几个特别容易被忽略的特性。

本文的完整demo。点击此处

<dialog>最基本的用法:

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

'open' 属性表示 <dialog>标签可见。如果不加'open'属性,<dialog>标签是默认不可见的,除非使用Javascript来设置使其显示。上面一段代码在页面上显示如下: 因为<dialog>在页面上是绝对定位,所以它会显示在其他元素前面并水平居中。默认宽度由内容所决定。

基本用法

JavaScript有几个方法和属性可以配合'<dialog>'来使用。最经常用到的方法是以下两个 'showModal()'和'close()'。

    const modal = document.querySelector('dialog');

    // 使元素显示 (添加 `open` 属性)
    modal.showModal();

    // 隐藏元素 (移除 `open` 属性)
    modal.close();

当使用'showModal()'使元素显示,页面会弹出遮罩层,阻止用户与非对话框的内容交互。遮罩层默认是完全透明的。如下:

dialog::backdrop {
    position: fixed;
    top: 0px;
    right: 0px;
    bottom: 0px;
    left: 0px;
    background: rgba(0, 0, 0, 0.1);
}

开发者可以通过css来设置遮罩层的样式。 按Esc键关闭对话框及遮罩层。也可以通过按钮来触发关闭。

<dialog>第三个方法 'show()', 同样也是让元素显示,但与'showModal()'不同的是没有遮罩层。 用户依然可以和页面上其他内容交互。

浏览器支持和兼容

目前,只有chrome浏览器支持<dialog>标签的样式及方法,而火狐仅支持样式,不支持方法。相信火狐不久之后就会支持的。

值得高兴的是,有一种方法可以使浏览器兼容这些方法和样式。通过npm安装 dialog-polyfill,或者通过<script>标签引入。 此插件支持IE9+ 使用polyfill,记得页面要进行初始化

dialogPolyfill.registerDialog(modal);

这种用法不会覆盖已支持<dialog>的浏览器自身的方法。

样式

<dialog>自带的打开或者关闭modal很好用,但是看起来不是特别专业,给它添加样式的方法与其他元素一样简单。遮罩层可以用伪元素 ::backdrop来设置:

dialog {
  padding: 0;
  border: 0;
  border-radius: 0.6rem;
  box-shadow: 0 0 1em black;
}

dialog::backdrop {
  /* 遮罩层设置为半透明 */
  background-color: rgba(0, 0, 0, 0.4);
}

但是,有些旧版本浏览器并不支持伪元素,因此 polyfill 在标签后面增加了 .backdrop,可以在css中使用:

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

增加.backdrop来应对css兼容性问题。

<dialog>对话框的常用方法是将其分解为header,body和footer:

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

添加一些样式,变成下面的样子:

更多用法

通常,我们希望从对话框中获得某种用户反馈,例如当关闭对话框时,可以传递一个值给close()方法,该值被指定给DOM元素的returnValue属性。用法如下:

modal.close('Accepted');

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

同样的,也可以监听很多事件。两个比较有用的就是 close() (关闭对话框时触发)和 cancel() (当用户按Esc键关闭对话框时触发)。

这里有一个功能貌似被忽略了,就是点击遮罩层时关闭对话框。别着急,有对应的解决办法。

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

点击遮罩层就会触发对话框内部的点击事件。如果对话框内的子元素占满了父元素,那么点击对话框内的任何地方都会通过target触发event事件。

这样一来便可以实现点击遮罩层关闭对话框功能了。 这种方法并不一定完美,但它确实是可行的。如果有更好的实现方法,可以分享出来一起探讨。