# 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表单,且formmethod属性为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 uiDialog (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.cssindex.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) 同步更新,欢迎关注😉~

最后更新时间: 3/6/2022, 9:06:37 PM