Popover API

Popover API: 内置的弹框能力

  • popover

具有 auto 状态的弹窗可以通过在弹窗之外的区域进行选择,以达到“轻触关闭”的目的,并且通常一次仅允许屏幕上显示一个弹窗
manual 弹窗必须始终明确隐藏,但可以用于菜单中嵌套弹窗等使用情况。

<button type="button" popovertarget="popover">打开弹窗 with popovertarget</button>
<div id="popover" class="popover" popover="auto">
  <div>弹窗内容</div>
</div>

  • popover="auto"

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Popover API</title>
    <style>
      .popover {
        --popover-status: none;

        padding: 20px;
        background-color: #fff;
        border-radius: 5px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);

        &::backdrop {
          background-color: rgba(0, 0, 0, 0.3);
        }
        &:popover-open {
          /* 弹窗显示动画 */
          animation: popover-in 0.24s ease;
        }
        &:not(:popover-open):not(dialog[open]) {
          display: var(--popover-status);
          /* 弹窗离开动画 */
          animation: popover-out 0.24s ease;
        }
      }

      @keyframes popover-in {
        from {
          opacity: 0;
          translate: 0 -100%;
        }
        to {
          opacity: 1;
          translate: 0 0;
        }
      }
      @keyframes popover-out {
        from {
          opacity: 1;
          translate: 0 0;
        }
        to {
          opacity: 0;
          translate: 0 -100%;
        }
      }
    </style>
  </head>
  <body>
    <strong>Popover API</strong>
    <hr />
    <button type="button" popovertarget="popover">打开弹窗 with popovertarget</button>
    <div id="popover" class="popover" popover="auto">
      <div>弹窗内容</div>
    </div>

    <script>
      // Popover API: 内置的弹框能力
      // 具有 auto 状态的弹窗可以通过在弹窗之外的区域进行选择,以达到“轻触关闭”的目的,并且通常一次仅允许屏幕上显示一个弹窗
      // manual 弹窗必须始终明确隐藏,但可以用于菜单中嵌套弹窗等使用情况。

      const popover = document.querySelector('.popover');

      popover.addEventListener('beforetoggle', (e) => {
        console.log('before toggle', e);
        // 阻止默认行为, 阻止弹窗显示
        // e.preventDefault();
      });
      popover.addEventListener('toggle', async (e) => {
        console.log('toggle', e);
      });

      const popoverAnimate = {
        'popover-in'() {
          popover.style.setProperty('--popover-status', 'unset');
        },
        'popover-out'() {
          popover.style.setProperty('--popover-status', 'none');
        },
      };
      popover.addEventListener('animationend', (e) => {
        popoverAnimate[e.animationName]?.();
      });
    </script>
  </body>
</html>
  • popover="manual"

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Popover API</title>
    <style>
      .popover {
        --popover-status: none;

        padding: 20px;
        background-color: #fff;
        border-radius: 5px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);

        &::backdrop {
          background-color: rgba(0, 0, 0, 0.3);
        }
        &:popover-open {
          /* 弹窗显示动画 */
          animation: popover-in 0.24s ease;
        }
        &:not(:popover-open):not(dialog[open]) {
          display: var(--popover-status);
          /* 弹窗离开动画 */
          animation: popover-out 0.24s ease;
        }
      }

      @keyframes popover-in {
        from {
          opacity: 0;
          translate: 0 -100%;
        }
        to {
          opacity: 1;
          translate: 0 0;
        }
      }
      @keyframes popover-out {
        from {
          opacity: 1;
          translate: 0 0;
        }
        to {
          opacity: 0;
          translate: 0 -100%;
        }
      }
    </style>
  </head>
  <body>
    <strong>Popover API</strong>
    <hr />
    <button type="button" id="btn-open">打开弹窗</button>
    <div class="popover" popover="manual">
      <div>弹窗内容2</div>
      <button type="button" class="btn-close">关闭弹窗</button>
    </div>

    <script>
      // Popover API: 内置的弹框能力
      // 具有 auto 状态的弹窗可以通过在弹窗之外的区域进行选择,以达到“轻触关闭”的目的,并且通常一次仅允许屏幕上显示一个弹窗
      // manual 弹窗必须始终明确隐藏,但可以用于菜单中嵌套弹窗等使用情况。

      const popover = document.querySelector('.popover');

      const openBtn = document.getElementById('btn-open');
      const closeBtn = document.querySelector('.btn-close');
      openBtn.addEventListener('click', () => {
        // 显示弹窗
        popover.showPopover();
      });
      closeBtn.addEventListener('click', () => {
        // 关闭弹窗
        popover.hidePopover();
      });

      popover.addEventListener('beforetoggle', (e) => {
        console.log('before toggle', e);
        // 阻止默认行为, 阻止弹窗显示
        // e.preventDefault();
      });
      popover.addEventListener('toggle', async (e) => {
        console.log('toggle', e);
      });

      const popoverAnimate = {
        'popover-in'() {
          popover.style.setProperty('--popover-status', 'unset');
        },
        'popover-out'() {
          popover.style.setProperty('--popover-status', 'none');
        },
      };
      popover.addEventListener('animationend', (e) => {
        popoverAnimate[e.animationName]?.();
      });
    </script>
  </body>
</html>

  • Element.animate
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Popover API</title>
    <style>
      .popover {
        --popover-status: none;

        padding: 20px;
        background-color: #fff;
        border-radius: 5px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);

        &::backdrop {
          background-color: rgba(0, 0, 0, 0.3);
        }
        &:not(:popover-open):not(dialog[open]) {
          display: var(--popover-status);
        }
      }
    </style>
  </head>
  <body>
    <strong>Popover API</strong>
    <hr />

    <button type="button" id="btn-open">打开弹窗</button>
    <div class="popover" popover="manual">
      <div>弹窗内容2</div>
      <button type="button" class="btn-close">关闭弹窗</button>
    </div>

    <script>
      // Popover API: 内置的弹框能力
      // 具有 auto 状态的弹窗可以通过在弹窗之外的区域进行选择,以达到“轻触关闭”的目的,并且通常一次仅允许屏幕上显示一个弹窗
      // manual 弹窗必须始终明确隐藏,但可以用于菜单中嵌套弹窗等使用情况。

      const popover = document.querySelector('.popover');

      const openBtn = document.getElementById('btn-open');
      const closeBtn = document.querySelector('.btn-close');
      openBtn.addEventListener('click', () => {
        // 显示弹窗
        popover.showPopover();
      });
      closeBtn.addEventListener('click', () => {
        // 关闭弹窗
        popover.hidePopover();
      });

      /** @type {Animation} */
      let animate;
      popover.addEventListener('beforetoggle', (e) => {
        console.log('before toggle', e);
        // 阻止默认行为, 阻止弹窗显示
        // e.preventDefault();

        if (e.newState === 'open') {
          animate = popover.animate(
            [
              {
                opacity: 0,
                translate: '0 -100%',
              },
              {
                opacity: 1,
                translate: '0 0',
              },
            ],
            {
              duration: 240,
              easing: 'ease',
              fill: 'forwards',
            }
          );
        }
        if (e.newState === 'closed') {
          animate = popover.animate(
            [
              {
                opacity: 1,
                translate: '0 0',
              },
              {
                opacity: 0,
                translate: '0 -100%',
              },
            ],
            {
              duration: 240,
              easing: 'ease',
              fill: 'forwards',
            }
          );
        }
      });
      popover.addEventListener('toggle', async (e) => {
        console.log('toggle', e);

        const isFinished = await animate.finished;
        if (e.newState === 'open') {
          popover.style.setProperty('--popover-status', 'unset');
        }
        if (e.newState === 'closed') {
          popover.style.setProperty('--popover-status', 'none');

          // or
          // animate.addEventListener('finish', () => {
          //   popover.style.setProperty('--popover-status', 'none');
          // });
        }
      });

      // or
      // const popoverAnimate = {
      //   'popover-in'() {
      //     popover.style.setProperty('--popover-status', 'unset');
      //   },
      //   'popover-out'() {
      //     popover.style.setProperty('--popover-status', 'none');
      //   },
      // };
      // popover.addEventListener('animationend', (e) => {
      //   popoverAnimate[e.animationName]?.();
      // });
    </script>
  </body>
</html>
posted @ 2024-04-30 13:27  _clai  阅读(15)  评论(0编辑  收藏  举报