美文网首页让前端飞Web前端之路
图解直到今天也没什么人知道的原生dialog标签😑

图解直到今天也没什么人知道的原生dialog标签😑

作者: 聪明的汤姆 | 来源:发表于2019-10-12 13:37 被阅读0次

    html5中,新增了很多语义化的标签。如footerheader之类的,今天的主角是dialog标签😂

    顾名思义,就是用来定义对话框的。目前只有ChromeSafari支持该标签,所以用的不多,不过确实挺好用的🤞

    别担心,有官方的polyfill

    image

    使用方法

    1. 基础的用法

    <dialog open>我是一个对话框</dialog>
    

    可以用open属性控制dialog是否显示,效果如下:

    image

    看看浏览器渲染的默认样式:


    image

    是挺丑的,而且默认还不是全屏居中有透明遮罩😭

    2. 使用JS API

    当然,也可以用JS来控制元素的显示跟隐藏。

    常用的有三个方法:

    名称 说明
    show 显示dialog元素(跟open属性控制一样)
    showModal 显示dialog元素,并且全屏居中,并带有黑色透明遮罩
    close 隐藏dialog元素

    简单的用法:

    <dialog>
      <p>我是一个对话框</p>
      <button onclick="hideDialog()">隐藏对话框</button>
    </dialog>
    
    <button onclick="showDialog()">显示对话框</button>
    
    <script>
      let dialog = document.querySelector("dialog");
      
      // 显示对话框
      function showDialog() {
        dialog.show();
      }
      
      // 隐藏对话框
      function hideDialog() {
        dialog.close();
      }
    </script>
    

    效果如下:


    image

    dialog.show()改成dialog.showModal(),看看效果:

    image

    就像上面介绍所说的"全屏居中,并带有黑色透明遮罩",看起来还不错😂

    默认样式倒没变,只是多加了一个::backdrop伪元素(透明遮罩):

    image

    3. 修改背景色

    想改背景颜色可以直接覆盖掉样式:

    dialog::backdrop {
      background: linear-gradient(45deg, black, transparent);
    }
    

    效果如下:


    image image

    多个对话框

    如果同时出现多个对话框,会根据调用的先后顺序叠加上去。

    假设布局如下(省略JS代码,因为大同小异):

    <dialog>
      <p>我是第一个对话框</p>
      <button onclick="hideDialog1()">隐藏对话框</button>
      <button onclick="showDialog2()">显示第二个对话框</button>
    </dialog>
    
    <dialog>
      <p>我是第二个对话框</p>
      <p>我是第二个对话框</p>
      <button onclick="hideDialog2()">隐藏对话框</button>
    </dialog>
    
    <button onclick="showDialog1()">显示第一个对话框</button>
    

    效果如下:


    image

    既然是叠加,那么背景色一定会叠加(同时存在多个dialog元素),这是必然的😂

    dialog本身的样式也可以修改,直接覆盖即可:

    dialog {
      border: none;
      border-radius: 8px;
    }
    

    效果如下:


    image

    点击遮罩关闭对话框

    目前并没有参数/属性可以设置"点击遮罩进行关闭对话框",但是这个需求很常见不是吗?

    思考了一会,那就自己实现一个吧😒,其实给dialog添加一个click事件,当点击的目标为遮罩的时候,然后把自己隐藏掉就行了。

    dialog.onclick = function(event) {
      console.log(event.target);
    };
    

    但是事实却没那么顺利:


    image

    无论你点哪里,目标元素都是dialog😭,但是,有一个非常机智的方法。

    image

    我把结构变成如下:

    <dialog>
      <div class="content">
        // 这是内容...
      </div>
    </dialog>
    

    然后把dialog默认的padding转移到.content上!

    dialog {
      padding: 0;
      
      .content {
        padding: 1rem;
      }
    }
    

    这样点击话,就可以区分出来啦😉


    image

    然后判断一下,大功告成:

    dialog.onclick = function(event) {
      if (event.target.tagName.toLowerCase() == "dialog") this.close();
    };
    

    效果如下:


    image

    把"可点击遮罩关闭"配置化

    我们约定一个属性closeByMask,若标签上存在该属性,则可以进行点击关闭:

    <dialog closeByMask></dialog>
    
    <dialog closeByMask></dialog>
    

    然后添加以下脚本即可:

    document.querySelectorAll("dialog[closeByMask]").forEach(dialog => {
      dialog.onclick = function(event) {
        if(event.target.tagName.toLowerCase() == "dialog") this.close();
      }
    });
    

    然后不管你怎么嵌套都行啦🤣

    假如两个dialog都存在closeByMask属性:

    image

    假如第二个dialog才存在closeByMask属性:

    image

    如何加过渡动画

    1. 使用animation

    dialog {
      animation: slideDown 0.2s ease;
    }
    
    @keyframes slideDown {
      from {
        transform: translateY(-100px);
      }
    
      to {
        transform: translateY(0);
      }
    }
    

    效果如下:


    image

    缺点:关闭的时候没有动画😭

    2. 使用transition

    没有open属性的dialog元素是被默认设置成display: none的。

    image

    众所周知transition是不支持display过渡的😭

    所以,我们得把display: none换成opacity: 0就可以支持过渡啦😉

    dialog {
       transition: opacity 0.4s ease;
       opacity: 1;
    }
    
    dialog:not([open]) {
      display: block;
      opacity: 0;
    }
    

    效果如下:


    image

    但是opacity只是设置透明度为而已,实际上dialog元素还是存在的,如果dialog里面绑定了点击事件,一样会执行,即使你看不见它😒

    比如这样:


    image

    不要慌嘻嘻,我们不是还有visibility属性吗哈哈哈💕,所以CSS代码改成如下:

    dialog:not([open]) {
      display: block;
      opacity: 0;
      visibility: hidden;
    }
    

    完美解决问题😁,并且显示跟隐藏都有过渡效果了。关于上述隐藏元素的方法,后面会专门出一篇文章详解。

    image

    大家有没有发现,遮罩背景并没有过渡效果,只是dialog元素本身有。

    我尝试写如下代码:

    dialog::backdrop {
      opacity: 1;
      transition: opacity 10s ease;
    }
    
    dialog:not([open])::backdrop {
      opacity: 0;
    }
    

    发现并没有效果,欢迎各位在评论补充或者纠正😘

    image

    浏览器兼容表

    image
    放心,这里有官方的polyfill

    dialog-polyfill

    最后

    如果你觉得这篇文章不错,请别忘记点个关注哦~😊

    交流

    微信公众号「前端宇宙情报局」,将不定时更新最新、实用的前端技巧/技术性文章,对了偶尔还会有互联网中的趣事趣闻🍻

    关注公众号,回复"1"加入微信学习群,一起学习、一起交流、一起摸鱼🌊

    image

    相关文章

      网友评论

        本文标题:图解直到今天也没什么人知道的原生dialog标签😑

        本文链接:https://www.haomeiwen.com/subject/knsqmctx.html