shadow dom

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shadow dom相关的知识,希望对你有一定的参考价值。

初识shadow dom

我们先看个input="range"的表现:

技术分享

what amazing ! 一个dom能表现出这么多样式嘛?

无论是初学者和老鸟都是不肯相信的,于是在好奇心的驱使下,我们打开chrome的开发工具设置

 技术分享

 

结果发现了input节点里面有我们需要的答案

技术分享

 

input节点里面有他表现需要的dom节点,dom节点里面还有些样式,而这些不容易为人知的节点都在一个#shadow-root的节点下面。

 

 来张图了解下结构

技术分享

 

document

这个很好理解,就是我们的正常文档 document 。

shadow host

对于一个内部有 shadow-dom 的元素而言,它必然需要一个宿主元素,对于上面的例子而言, <input> 标签,就是 shadow-dom 的宿主元素。

shadow-root

通过 createShadowRoot(下文会提及) 返回的文档片段被称为 shadow-root 。它和它的后代元素,都将对用户隐藏,但是它们是实际存在的,在 chrome 中,我们可以通常审查元素去查看它们的具体 DOM 实现。

在 此例子的 input 中,例如滑块,滑块条等都是 shadow-root 的后代。它们工作时会显示在屏幕上,但他们的 DOM 结构对用户是不可见的。

contents

就是上述所说的 input 中各子组件的 DOM 的具体实现。

shadow dom的api

下文先从例子出发学习api,再由API了解shadow dom的特性,不失为学习的好方法

helloWord

1 <div class="widget"></div>  
2 <script>  
3     var host = document.querySelector(.widget);
4     var root = host.createShadowRoot();
5     root.textContent = hello world!;
6 </script> 

页面的效果是

技术分享

 

dom结构也和想象中一样:在div.widget>shadow-root>text(hello world)

技术分享

shadowHost.createShadowRoot:在shadowHost内创建ShadowRoot节点
dom操作
再来个简单的例子
<body>
   <div class="widget">Hello, world!</div>3   <script>
     var host = document.querySelector(.widget);
     var root = host.createShadowRoot();
 
     var header = document.createElement(h1);
    header.textContent = 影子标题;
 
     var paragraph = document.createElement(p);
     paragraph.textContent = 影子文本;
 
     root.appendChild(header);
     root.appendChild(paragraph);
   </script>
 </body>

 


效果和dom结构也和想象中一样,只是div.widget(shadowHost)内的内容不见了,没错,在有shadowDom的情况下ShadowHost内的真实节点并不会渲染。
技术分享

 

技术分享

从这个例子发现普通的dom操作在shadowDom也是可行的

template/content

在之前的例子里,我们用shadow root里面的内容完全替换掉了shdow host里面的内容。但这种奇技淫巧在实际开发中没什么用。真正有用的是我们可以从shdow host中获取内容,并使用shdow root中的结构将这些内容呈现

<body>
  <div class="widget">
    ShadowRootText
  </div>

  <template class="template">
    <h1>ShadowRoot的内容出现了 <content>ShadowRootText</content> 出现了!</h1>
  </template>

  <script>
    var host = document.querySelector(.widget);
    var root = host.createShadowRoot();
    var template = document.querySelector(.template);
    root.appendChild(document.importNode(template.content, true));
  </script>
</body>

效果如下

技术分享

dom结构也是想象中的那样:shadow host里面的内容都插进了shadow root的content节点里面了

技术分享

使用 <content> 标签,我们创建了一个insertion point(<content>),其将 div.pokemon 中的文本projects 出来,使之得以在我们的影子节点 <h1> 中展示。

插入点十分强大,它允许我们在不改变源代码的情况下改变渲染顺序,这也意味着我们可以对要呈现的内容进行选择。

select 属性

 

<body>
  <div class="widget">
    <span class="contury">中国</span>
    <span class="city">广州</span>
    <span class="province">广东</span>
    <p>广州好很塞车</p>
  </div>

  <template class="template">
    <dl>
      <dt>国家</dt>
      <dd><content select=".contury"></content></dd>
      <dt>省份</dt>
      <dd><content select=".province"></content></dd>
      <dt>城市</dt>
      <dd><content select=".city"></content></dd>
    </dl>
    <p><content select=""></content></p>
  </template>

  <script>
    var host = document.querySelector(.widget);
    var root = host.createShadowRoot();
    var template = document.querySelector(.template);
    root.appendChild(template.content);
  </script>
</body>

 

 页面效果

技术分享

dom结构

技术分享

 

在这个例子中,content里面能选择shadow root里面的insertion point能通过select属性选择出shadow host里面的内容,

并且,页面显示顺序是按照shadow root里面的template顺序显示,并不会按照shadow host的数据显示顺序显示,由此可发现

shadow root 负责渲染的结构、顺序,shadow host负责渲染的数据(接触过angularJS的directive的你是否看完后是否会微微一笑)

贪心插入点

<body>
  <div class="widget">
   <p>shadow host text</p>
  </div>

  <template class="template">

    <p><content ></content>
    <p><content select=""></content>
    <p><content select="*"></content>
  
  </template>

  <script>
    var host = document.querySelector(.widget);
    var root = host.createShadowRoot();
    var template = document.querySelector(.template);
    root.appendChild(template.content);
  </script>
</body>

template有三个content,三个content都是匹配shadow host的内容的,那么显示的效果是三行文本还是一行呢?

结果显示是这样的

技术分享

 

dom结构是这样的

技术分享

 

 这是因为这个选择器是贪心的,而且元素只能被选择一次。我们一旦把贪心选择器匹配了shadow host的内容,他就会将所有内容都抓取,不给其他 select 选择器留一点内容。



 

以上是关于shadow dom的主要内容,如果未能解决你的问题,请参考以下文章

Firefox:shadow-DOM 兼容性

shadow-dom浅析

shadow-dom 浅析

神秘的 shadow-dom 浅析

虚拟DOM(Virtual Dom) VS 影子DOM(Shadow Dom)

Ruby:在 Shadow-Root DOM 中获取 Web 元素