• 浅谈shadow dom


    什么是shadow dom?

    顾名思义, shadow-dom,直译的话就是 影子/隐蔽处的dom ?我觉得可以理解为潜藏在背后的 DOM 结构,也就是我们无法直接控制操做的 DOM 结构。
    在这里插入图片描述

    它相当于一个作用域的概念,使其不会被外部所影响。可以把它理解成一颗单独的dom树。这样就不会有css的命名冲突或者样式的意外泄漏。
    在chrome里,我们可以启用开发者工具的“Show user agent shadow DOM”选项,就能看到这些隐藏的结构。

    举例:
    video标签: 虽然我们创建的是一个空标签,但是在这个空标签内部,存在一个 shadow-dom ,点开 shadow-dom 可以看到里面的内容。其实这内部的具体内容,就是 的具体实现。
    在这里插入图片描述

    shadow DOM视为“DOM中的DOM”。它是独立的DOM树,具有自己的元素和样式,与原始DOM完全隔离。可以应用在组件中。

    在一些微前端框架,例如qiankun的源码时,发现qiankun在实现css样式的隔离时,使用了shadow DOM

    有什么特点?

    可以使用和操作常规 DOM 一样的方式来操作 Shadow DOM,例如添加子节点、设置属性,以及为节点添加自己的样式
    Shadow DOM 内部的元素始终不会影响到它外部的元素(除了 :focus-within),这为封装提供了便利。

    有什么用?

    1、良好的封装性,对于通用的组件来说,我们作为开发者,其实并不需要关心内部很多元素的实现或原理,比如我们在页面中使用 video 标签,其实对于暂停,播放,拖动滚动条等逻辑并不需要做过多的关心,那么我们希望代码越简洁越好,就像现在一样,只需要一个video标签即可,而不是还要写一堆元素来实现本身的播放暂停等按钮
    2、现行的组件都是开放式的,即最终生成的 HTML DOM 结构难以与组件外部的 DOM 进行有效结构区分,样式容易互相混淆。Shadow-dom 的 封装隐藏性为我们提供了解决这些问题的方法。

    为什么需要 shadow-dom?

    Shadow-dom 是游离在 DOM 树之外的节点树,但是他的创建基于普通 DOM 元素(非 document),并且创建后的 Shadow-dom 节点可以从界面上直观的看到。更重要的是,Shadow-dom 具有良好的密封性。这是浏览器提供的一种“封装”功能,提供了一种强大的技术去隐藏一些实现细节
    怎么创建shadow dom?
    要创建一个shadow DOM。首先我们需要一个Shadow root,Shadow root 是 shadow 树中最顶层的节点, 是在创建 shadow DOM 时被附加到常规DOM节点的内容。具有与之关联的shadow root的节点称为shadow host。(如下图所示)
    在这里插入图片描述在这里插入图片描述

    像上图,shadowHost就是div.shadow-dom。这个外层的css会影响到他。(要注意:css样式的边界影响,就是不要给shadowhost或者他的父级定义可以遗传的样式,可以用all: initial还原)。

    使用 attachShadow 创建shadowDom:
    let shadow = element.attachShadow({mode: ‘open’});
    let shadow = element.attachShadow({mode: ‘closed’});
    open / closed 表示可否通过页面内的 JavaScript 方法来获取 Shadow DOM

    创建shadow DOM需要注意以下几点:
    1.只有封闭标签才能作为shadowHost。
    2.当我们把一个标签设置成shadow DOM的时候,里面的子元素将全部失效。
    3.当mode为closed时,禁止你使用host元素的shadowRoot属性从root外部访问shadow root的元素。
    如何修改shadow dom的样式?
    1、在shadow块下面创建style标签,在里面添加样式
    2、mode为true时,通过shadowRoot获取到指定元素修改样式
    试试?
    示例中有两个div的className都是cn,一个在普通dom中,一个在shadowDom中。可以看到两个style标签下的cn样式互不影响

    <!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>
      <style>
        .cn {
          color: red;
        }
        .shadow-dom {
          /* 可继承 */
          background-color: yellow;
          text-indent: 2em;
          /* 将所有css属性恢复到初始状态 */
          all: initial;
        }
      </style>
    </head>
    <body>
      <div class="wrapper">
        <div class="cn">dom</div>
        <div class="shadow-dom">test</div>
      </div>
    </body>
    <script>
      const shadowHost = document.querySelector('.shadow-dom');
      const shadowRoot = shadowHost.attachShadow({mode: 'open'});
    
    
      const div = document.createElement('div');
      div.innerHTML = "shdow-dom";
      div.className = 'cn'
      div.setAttribute('part', 'native')
    
    
      const style = document.createElement('style');
      style.textContent = `
        .cn {
          color: blue;
        }
      `;
      
      shadowRoot.appendChild(style)
      shadowRoot.appendChild(div)
      // shadowHost.shadowRoot.querySelector('.cn').style.color = 'green'
    
      console.log('shadowRoot', shadowHost.shadowRoot)
      
    </script>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    shadow-dom 的未来

    现行的组件都是开放式的,即最终生成的 HTML DOM 结构难以与组件外部的 DOM 进行有效结构区分,样式容易互相混淆。Shadow-dom 的 封装隐藏性为我们提供了解决这些问题的方法。在 Web 组件化的规范中也可以看到 Shadow-dom 的身影,使用具有良好密封性的 Shadow-dom 开发下一代 Web 组件将会是一种趋势。

  • 相关阅读:
    MySQL-json字段的使用
    react-router-dom V5版本 路由搭建
    LabVIEW在不同平台之间移植VI
    大厂面试题Object object = new Object()
    C++ 派生类函数重载与虚函数继承详解
    docker容器启动rabbitmq
    【蓝桥】健身
    全局异常拦截和Spring Security认证异常的拦截的顺序
    9. android 动态音频策略的原理
    WebSocket Day04 : 消息推送
  • 原文地址:https://blog.csdn.net/qq_42872073/article/details/125607826