🐵 原生模态对话框了解一下?

1,478 阅读2分钟

在正文的第一句加入“我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!

在业务开发中,模态对话框(Modal Dialog)是常用的组件,主要用途是在用户处理重要事务/操作时,进行信息展示/二次确认⚠️等,而不用离开当前页面。

image.png 图为 Antd Modal

通常项目中我们会使用成熟框架提供的 Modal 组件,你是否知道,其实 HTML 5.2 (2018) 也提供了原生的 Dialog 元素。这篇文章就一起来学习如何使用原生 Dialog 吧。

Dialog

学习一个新知识点,最快的上手的方式是自己动手写 Demo,这里直接上代码看示例。

HTML 代码非常简单如下所示,之前你可能没听说过 dialog 标签,现在你应该知道了,它也是 HTMLElement 的子类 HTMLDialogElement。

<dialog class="modal" id="modal">
  <div class="modal-content">
    <div class="modal-header"><div class="modal-title">标题</div></div>
    <div class="modal-body">
      <p>正文...</p>
      <p>正文...</p>
      <p>正文...</p>
    </div>
    <div class="modal-footer">
      <button type="button" class="btn btn-default" id="cancel-btn"><span>取 消</span></button>
      <button type="button" class="btn btn-primary" id="ok-btn"><span>确 定</span></button>
    </div>
  </div>
</dialog>

属性: open

默认情况下 dialog 元素不可见,除非给它加上 open 属性。

<dialog class="modal" id="modal" open>
   ...
</dialog>

浏览器自带的 stylesheet 会让 dialog 元素默认呈现水平居中效果。

image.png

方法: show/showModal/close

除了设置 open attribute,还可以调用 dialog 的 show/showModal/close 方法来让控制其展示与否。

$$.showBtn.addEventListener('click', () => {
  $$.modal.show();
})

$$.showModalBtn.addEventListener('click', () => {
  $$.modal.showModal();
})

$$.cancelBtn.addEventListener('click', () => {
  $$.modal.close()
})

showshowModal 的区别是,show 只是 dialog 让元素可见(相当于设置 open=true),showModal 则会让 dialog 呈现模态效果,需要将模态框关闭之后才能和页面上其他元素交互。

落到具体实现上,当点击 showModal 时,浏览器会在 dialog 内部增加 ::backdrop 伪元素。

伪元素 ::backdroop

伪元素是啥?和 ::before/::after 是一类东西~

浏览器自带的 stylesheet 会让 ::backdropdialog 都变成 position: fixed,以达到遮盖页面其他元素的效果。

image.png

可以通过 ::backdrop 自定义这层遮罩的样式,就像这样。

image.png

事件:cancel/close

dialog 还提供了原生事件:

  1. cancel 在模态框展示时按下 Esc 按键,那么模态框将自动关闭,并触发 cancel 事件;
  2. close 则是在每次 dialog 元素由 open=true 变为 open=false 时触发;

属性: returnValue

close 方法还支持接收一个参数,这个参数被赋值给 dialog.returnValue。

$$.okBtn.addEventListener('click', () => {
  $$.modal.close('Ok')
})

$$.modal.addEventListener('close', () => {
  // 在这里获取 returnValue 将读到 "Ok"
  $$.result.innerHTML = $$.modal.returnValue
})

伪类 :modal

上面提到 showModal 方法被调用时,dialog 内会插入伪元素 backdrop,并且应用 position: fixed。而 dialog 元素本身的样式则是通过另一个伪类选择器 :modal

image.png

MDN 文档上看,:modal 伪类会匹配具有交互排它性的元素,例如模态框或者调用 requestFullscreen 方法的元素。

到这里, <dialog> 的知识普及环节就结束了。接下来我们尝试给它的出现/消失加上动画效果。

✨ Bonus

Bonus1 加入出现/消失动画

可以使用 :modal 伪类选择器来轻松实现模态框出现动画。

.modal:modal {
  animation: fadeInUp 0.3s;
}

@keyframes fadeInUp {
}

消失动画则可以是监听 animationend event 来实现,在尝试关闭时触发关闭动画,将 dialog.close 方法放到消失动画结束再调用。

.modal.leaving {
  animation: fadeOutDown 0.3s;
}

@keyframes fadeOutDown {
}
$$.modal.addEventListener('cancel', () => {
  // $$.modal.close('Cancelled by event')
  requestCloseModal('Cancelled by event')
})

function requestCloseModal (msg) {
  $$.modal.classList.add('leaving')
  $$.modal.addEventListener('animationend', () => {
    $$.modal.close(msg)
    $$.modal.classList.remove('leaving')
  }, {
    once: true
  })
}

Bonus2 支持 maskClosable

日常使用时,还会希望点击遮罩时,模态框也能退出,dialog 不支持这样的 API。我们可以通过给 modal 添加点击事件,判断 event.target 来实现。

$$.modal.addEventListener('click', (event) => {
  if (event.target === $$.modal) {
    requestCloseModal('Cancelled by backdrop');
  }
});

兼容性

当前(20220909) dialog 的浏览器支持率是 92.18%,不过 Chrome 团队也给出了 dialog-polyfill~

image.png

结束

又学到了一个新的知识点,祝大家中秋节🎑快乐。

相关链接