【问题标题】:How to close the new html <dialog> tag by clicking on its ::backdrop如何通过单击 ::backdrop 来关闭新的 html <dialog> 标签
【发布时间】:2014-11-09 22:28:49
【问题描述】:

我没有找到任何内置的解决方案或解决方法来通过单击其背景 (::backdrop) 来关闭 html5 元素,尽管它显然是一个基本功能。

【问题讨论】:

    标签: html google-chrome dialog opera pseudo-element


    【解决方案1】:

    如果您使用click,即使您从对话框的内部拖动到外部,它也会关闭对话框,这可能很烦人。

    您可以使用pointerdownpointerup 更准确地检测外部点击。

    // Close a dialog when the user clicks outside of it
    // Not using click because form submit can trigger click on submit button,
    // and also it would close if you drag from within the dialog to the outside
    // (e.g. if you're selecting text, or perhaps you start clicking the close button and reconsider)
    function clickOutsideToClose(dialog) {
        function isOutsideDialog(event) {
            const rect = dialog.getBoundingClientRect();
            return (
                event.clientX < rect.left ||
                event.clientX > rect.right ||
                event.clientY < rect.top ||
                event.clientY > rect.bottom
            );
        }
        addEventListener("pointerdown", function (event) {
            if (event.target !== dialog) {
                return;
            }
            if (isOutsideDialog(event)) {
                addEventListener("pointerup", function (event) {
                    if (isOutsideDialog(event)) {
                        closeSettings();
                    }
                }, { once: true });
            }
        });
    }
    

    到目前为止,我还没有尝试过 div 内容包装方法。也许这也解决了这个问题,或者可以解决这个问题?

    【讨论】:

      【解决方案2】:

      @Seralo 答案的简化版本是:

      dialog.addEventListener("click", event => {
          const rect = dialog.getBoundingClientRect();
          if (event.clientY < rect.top || event.clientY > rect.bottom ||
              event.clientX < rect.left || event.clientX > rect.right) {
              dialog.close();
          }
      };
      

      【讨论】:

        【解决方案3】:

        另外一个类似于其他人提到的wrapped div方法的简单方法是给对话框本身padding: 0(比如Chrome倾向于给对话框填充),并在对话框中添加点击事件。 form 元素无论如何都会获得差异,因此不需要额外的 div。 我注意到在上面的任何示例中都没有使用该表单,所以我认为这是值得投入使用的,因为它是在对话框中使用按钮时的标准的一部分。

        <dialog style="padding: 0; border: 0;">
          <form method="dialog">
            <button>Click here</button>
          </form>
        </dialog>
        
        <script>
        function onClick(event) {
          if (event.target === dialog) {
            dialog.close();
          }
        }
        
        const dialog = document.querySelector("dialog");
        dialog.addEventListener("click", onClick);
        dialog.showModal();
        </script>
        

        Demo on CodePen

        【讨论】:

        • 这将适用于覆盖对话框的任何元素;干得好,包括符合规范的表格。
        【解决方案4】:

        我想出了一个非常简单的解决方案来解决这个问题。在&lt;dialog&gt; 中添加一个 div 容器。然后检查这是否是整个事情的父母。如果不是,就是对话框本身,可以关闭。

        HTML

        <dialog id="favDialog">
          <div class="test">
          Hello
          </div>
        </dialog>
        

        JS

        document.querySelector('dialog').addEventListener('click', function(e) {
          if(!e.target.closest('div')) {
            e.target.close();
          }
        });
        

        【讨论】:

        • 这是一个非常好的解决方案,因为它引用了对话框本身,而不是让我编写 ID 150 X 引用的其他代码。
        【解决方案5】:

        对于遇到此问题并希望遵循@meaku 推荐的解决方案的任何人,以下是我如何解决它以使用 a 封装元素而不使用 getBoundingClientRect() 计算:

        const popup = document.getElementById('popup');
        const popupDialog = document.getElementById('popup-dialog');
        popup.addEventListener('click', function(e){
          console.info(e.target.tagName);
          if (e.target.tagName === 'DIALOG') popupDialog.close()
        });
        <div id="popup" style="padding: 0">
            <dialog id="popup-dialog" style="display:none;">
                <h4>Dialog Title</h4>
                <footer class="modal-footer">
                    <button id="popup-close" type="button">close</button>
                    <button id="popup-ok" type="button">ok</button>
                </footer>
            </dialog>
        </div>

        【讨论】:

        • 这不是@meaku 推荐的。
        【解决方案6】:

        另一个更有效的解决方案是将dialog-content 包装在带有padding: 0div 中。这样,您可以检查单击事件的event.target,它在背景的情况下引用对话框,在实际模式的情况下引用div 中的任何其他元素。

        通过不检查实际尺寸,我们可以防止布局循环。

        【讨论】:

          【解决方案7】:

          可以使用对话框边界矩形检测背景点击。

          var dialog = document.getElementByTagName('dialog');
          dialog.showModal();
          dialog.addEventListener('click', function (event) {
              var rect = dialog.getBoundingClientRect();
              var isInDialog=(rect.top <= event.clientY && event.clientY <= rect.top + rect.height
                && rect.left <= event.clientX && event.clientX <= rect.left + rect.width);
              if (!isInDialog) {
                  dialog.close();
              }
          });
          

          【讨论】:

          • 我还必须检查event.targetdialog。例如if (!isInDialog &amp;&amp; event.target.tagName === 'DIALOG')。如果通过点击“enter”在对话框中提交表单,则单击事件事件将从提交按钮冒泡,并且由于某种原因,它的 clientX 和 clientY 为 0。
          • @kmurph79 在下面试试我的答案 - 它不需要检查边界客户矩形。
          • 有什么理由不用rect.rightrect.bottom 而不是rect.left + rect.widthrect.top + rect.height
          猜你喜欢
          • 2011-05-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-03
          • 2016-02-12
          • 2011-03-04
          • 1970-01-01
          相关资源
          最近更新 更多