如何用纯原生 JS 封装一个组件(四):shadom dom

5,713 阅读2分钟

「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」。

前情回顾

  • 前面一篇文章,我们提到了 web compontens 是一套原生 JavaScript 就已经支持组件封装的技术,它主要由三个技术组成:自定义元素,HTML 模板,影子 DOM
  • 然后我们也介绍了自定义元素、template 与 slot 的用法
  • 这篇文章会介绍一下,在之前的示例 demo 中用到的 shadom dom 相关知识

shadom dom

  • 它就是原生 javascript 提供的 api
  • 可以在一个普通 dom 节点上添加一个独立的,对外界隐藏的 dom 结构,可以是一棵 dom 树,也可以一组特定功能的 dom 结构
  • 添加的 dom 结构类似于处在一个沙箱环境中,内部元素的样式不会影响到外部的元素样式
  • 我们称之为 shadom dom,下面是一些关于 shadom dom 的名词解释
    • Shadow Host 是一个常规 DOM 节点,Shadow DOM 会被附加到这个节点上,相当于宿主元素
    • Shadow Tree 指的就是 Shadow DOM 内部的 DOM 树结构
    • Shadow Root 指的就是 Shadow Tree 的根节点
    • Shadow Boundary 指的是 Shadow DOM 的边界,也就是 Shadom Dom 结束的地方,也是接下来的常规 DOM 开始的地方
  • 接下来我们写个 demo 感受一下 shadom dom 的魅力
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <my-com myTitle="myCom-title">
      <div>my-com template</div>
      <span slot="s1">这是 s1 具名插槽</span>
      <span slot="s2">这是 s2 具名插槽</span>
      <span slot="s3">这是 s3 具名插槽</span>
    </my-com>

    <hr />

    <div>other</div>
  </body>

  <script>
    class MyCom extends HTMLElement {
      constructor() {
        super();
        console.log(this);

        // props
        const title = this.getAttribute("myTitle");

        // template、slot 搭配 shadow dom
        const templateDom = document.createElement("template");
        templateDom.innerHTML = `
          <style>
            div{
              background: teal;
            }
          </style>
          <div>
            <h2 class="title">template demo title:${title}</h2>
            2222-【<slot name="s2"></slot>】-2222
            <br />
            3333-【<slot name="s3"></slot>】-3333
            <br />
            1111-【<slot name="s1"></slot>】-1111
          </div>
        `;

        const divTemplate = templateDom.content;

        // let shadowDom = this.attachShadow({ mode: "closed" }); 
        let shadowDom = this.attachShadow({ mode: "open" }); 
        
        shadowDom.append(divTemplate);
      }
    }

    customElements.define("my-com", MyCom);
  </script>
</html>
  • 下面是页面效果 image.png

  • 代码没有太多变化,还是在上篇文章的代码基础上做了一点改变

  • 我们给内部的 shadom 加上了一点样式

    • 给内层 div 设置了 background 的颜色为 teal
    • 正常来讲,外部的 div 的 background 的颜色也会被设置为 teal
    • 但是由于内部 shadom dom 相对于外部是隐藏起来的,类似于一个沙箱环境
    • 所以内部 shadom dom 的样式,不会影响到外部元素
  • Element.attachShadom 就是添加 shadom dom 的关键 api

    • 这个方法接受一个对象,其中有个属性,mode
      • 值为 "open" 时,代表可以通过页面内的 JavaScript 方法来获取对应的 shadom dom
      • 值为 "closed" 时,表示无法使用 JavaScript 在页面上获取对应的 shadom dom
    • 下面打印一下 shadom dom
let shadowDom = this.attachShadow({ mode: "open" });
console.log(shadowDom);

image.png

let shadowDom = this.attachShadow({ mode: "closed" });
console.log(shadowDom);

image.png

小结

  • 到这里 shadom dom 的基本使用就介绍的差不多了
  • 下篇文章,我会将 web component 的三大件组合在一起,实战写一个弹窗组件

最后

  • 今天的分享就到这里了,欢迎大家在评论区里面进行讨论 👏。
  • 如果觉得文章写的不错的话,希望大家不要吝惜点赞,大家的鼓励是我分享的最大动力 🥰