97

什么是Shadow DOM?

 5 years ago
source link: https://segmentfault.com/a/1190000017970486?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

什么是Shadow DOM?

几周前,我写了一篇关于 究竟是什么DOM 的文章。回顾一下,文档对象模型是HTML文档的表示。浏览器使用它来确定页面上要呈现的内容,并通过Javascript程序来修改页面的内容,结构或样式。

例如,让我们采用以下HTML文档:

<!doctype html>
<html lang="en">
 <head>
   <title>My first web page</title>
  </head>
 <body>
    <h1>Hello, world!</h1>
    <p>How are you?</p>
  </body>
</html>

上面的HTML文档将产生以下DOM树。

  • html

    • head

      • title

        • My first web page
    • body

      • h1

        • Hello, world!
      • p

        • How are you?

在过去几年中,您可能听说过“Shadow DOM”和“Virtual DOM”等术语。这些虽然当然与原始DOM有关,但它们指的是截然不同的概念。在本文中,我将详细介绍Shadow DOM以及它与原始DOM的区别。在以后的文章中,我将对虚拟DOM进行分析。

一切都是 global 的:+1|type_5:!等等,一切都是 global 的:-1|type_5:

HTML文档中的所有元素和样式以及DOM都位于一个全局范围内。页面上的任何元素都可以通过 document.querySelector() 方法访问,无论它在文档中的嵌套程度如何或放置在何处。同样,应用于文档的CSS可以选择任何元素,无论它在何处。

当我们想要将样式应用于整个文档时,可以直接使用 * 选择页面上的每个元素并将它们的盒模型进行修改。 box-sizing

* { box-sizing: border-box }

另一方面,有些时候元素需要完全封装,我们不希望它受到全局样式的影响。一个很好的例子是第三方小部件,例如Twitter的“关注”按钮。以下是该小部件的示例:

Follow @ireaderinokun

aqQrM36.png!web

Twitter follow @ireaderinokun

假设您启用了Javascript并且检查了元素,您会注意到该按钮是一个<iframe>元素,您实际看到的样式按钮其实是加载一个小文档。

AnAnUbQ.png!web

这是Twitter可以确保其小部件的预期样式不受文档中的任何CSS影响的唯一方式。尽管有一些方法可以使用级联来尝试实现相同的结果,但是没有其他方法可以提供与<iframe>相同的效果。

创建Shadow DOM是为了允许在Web平台上本地封装和组件化,而不必依赖像<iframe>这样的工具,而这些工具实际上并不是为此目的而制作的。

DOM中的DOM

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

虽然最近才指定供Web作者使用,但用户代理多年来一直使用shadow DOM来创建和设置复杂组件(如表单元素)。我们来看一下input。要在页面上创建一个,我们所要做的就是添加以下元素:

<input type="range">

如果我们深入挖掘,我们会看到这个<input>元素实际上是由几个较小的<div>元素组成,控制着轨道和滑块本身。

zInu2iF.png!web

这是使用shadow DOM实现的。暴露给主机HTML的元素记录了简单的<input>,但在其下面有与组件相关的元素和样式,它们不构成DOM全局​​范围的一部分。

shadow DOM如何工作

为了说明shadow DOM的工作原理,让我们使用shadow DOM而不是<iframe>来重新创建Twitter“follow”按钮。

首先,我们从shadow host开始。这是我们想要将新影子DOM附加到原始DOM中的常规HTML元素。对于像Follow按钮这样的组件,它还可以包含我们希望在页面上未启用Javascript或不支持shadow DOM时显示的回退元素。

<span class="shadow-host">
  <a href="https://twitter.com/ireaderinokun">
     Follow @ireaderinokun
  </a>
</span>

请注意,我们不仅仅使用 <a> 元素作为影子主机,因为某些元素(主要是交互元素)不能是影子主机。

要将阴影DOM附加到我们的主机,我们使用attachShadow()方法。

const shadowEl = document.querySelector(".shadow-host");
const shadow = shadowEl.attachShadow({mode: 'open'});

这将创建一个空的shadow root作为我们的shadow host的子项。shadow root 是新的shadow DOM的开始,其方式是 <html> 元素是原始DOM的开头。我们可以通过#shadow-root 在devtools检查器中看到我们的shadow-root。

I3Ajiaz.png!web

虽然常规HTML子项在检查器中是可见的,但是当shadow root接管时,它们在页面上不再可见。

接下来,我们要创建内容以形成新的shadow tree。shadow tree就像一个DOM树,但是对于shadow DOM而不是常规DOM。要创建我们的跟随按钮,我们所需要的只是一个新的 <a> 元素,它与我们已有的后备链接几乎完全相同,但带有一个图标。

const link = document.createElement("a");
link.href = shadowEl.querySelector("a").href;
link.innerHTML = 
    <span aria-label="Twitter icon"></span> 
    ${shadowEl.querySelector("a").textContent}
;

我们将这个新元素添加到我们的shadow DOM中,就像使用 appendChild() 方法将任何元素作为子元素添加到另一个元素一样。

shadow.appendChild(link);

在这一点上,这是我们的元素的样子:

https://p0.ssl.qhimg.com/t012...

A3maUjj.png!web

最后,我们可以通过创建一个<style>元素并将其附加到阴影根来添加一些样式。

const styles = document.createElement("style");
styles.textContent = 
a, span {
  vertical-align: top;
  display: inline-block;
  box-sizing: border-box;
}

a {
    height: 20px;
    padding: 1px 8px 1px 6px;
    background-color: #1b95e0;
    color: #fff;
    border-radius: 3px;
    font-weight: 500;
    font-size: 11px;
    font-family:'Helvetica Neue', Arial, sans-serif;
    line-height: 18px;
    text-decoration: none;   
}

a:hover {  background-color: #0c7abf; }

span {
    position: relative;
    top: 2px;
    width: 14px;
    height: 14px;
    margin-right: 3px;
    background: transparent 0 0 no-repeat;
    background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2072%2072%22%3E%3Cpath%20fill%3D%22none%22%20d%3D%22M0%200h72v72H0z%22%2F%3E%3Cpath%20class%3D%22icon%22%20fill%3D%22%23fff%22%20d%3D%22M68.812%2015.14c-2.348%201.04-4.87%201.744-7.52%202.06%202.704-1.62%204.78-4.186%205.757-7.243-2.53%201.5-5.33%202.592-8.314%203.176C56.35%2010.59%2052.948%209%2049.182%209c-7.23%200-13.092%205.86-13.092%2013.093%200%201.026.118%202.02.338%202.98C25.543%2024.527%2015.9%2019.318%209.44%2011.396c-1.125%201.936-1.77%204.184-1.77%206.58%200%204.543%202.312%208.552%205.824%2010.9-2.146-.07-4.165-.658-5.93-1.64-.002.056-.002.11-.002.163%200%206.345%204.513%2011.638%2010.504%2012.84-1.1.298-2.256.457-3.45.457-.845%200-1.666-.078-2.464-.23%201.667%205.2%206.5%208.985%2012.23%209.09-4.482%203.51-10.13%205.605-16.26%205.605-1.055%200-2.096-.06-3.122-.184%205.794%203.717%2012.676%205.882%2020.067%205.882%2024.083%200%2037.25-19.95%2037.25-37.25%200-.565-.013-1.133-.038-1.693%202.558-1.847%204.778-4.15%206.532-6.774z%22%2F%3E%3C%2Fsvg%3E);
}
;

shadow.appendChild(styles);

这是我们的最后一个要素:

aqQrM36.png!web

DOM与shadow DOM

在某些方面,shadow DOM是DOM的“精简”版本。与DOM一样,它是HTML元素的表示,用于确定在页面上呈现的内容并启用元素的修改。但与DOM不同,shadow DOM不是基于完整的独立文档。正如其名称所示,shadow DOM始终附加到常规DOM中的元素。没有DOM,shadow DOM就不存在了。

Share the Article on Twitter

Share the Article on Facebook

Post the Article to Reddit


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK