36

这个问题更针对用户创建的影子 DOM 元素,但为了便于访问,我将使用date输入类型来回答这个问题:

比如说我date在我的页面上有一个输入。编辑了一些位,这个(使用 Chrome)的影子 DOM 标记看起来像:

<input type="date">
    #document-fragment
        <div pseudo="-webkit-datetime-edit">
            <div pseudo="-webkit-datetime-edit-fields-wrapper">
                <span role="spinbutton">dd</span>
                <div pseudo="-webkit-datetime-edit-text">/</div>
                <span role="spinbutton">mm</span>
                <div pseudo="-webkit-datetime-edit-text">/</div>
                <span role="spinbutton">yyyy</span>
            </div>
        </div>
        <div></div>
        <div pseudo="-webkit-calendar-picker-indicator"></div>

与输入关联的方法和属性date似乎根本没有引用影子 DOM ( JSFiddle ),所以我想知道如何(如果有的话)可以访问这些影子 DOM 元素?

4

4 回答 4

21

@int32_t 是正确的,根据定义,Shadow DOM 是一种使用要从外部源(封装)隐藏的 DOM 填充节点的方法。关键是,作为组件作者,您可以准确选择哪些部分将暴露给 CSS 或 JavaScript 之外,哪些不暴露。

不幸的是,如果不使用另一个名为Custom Elements的前沿规范,就无法为 Shadow DOM 创建公共 JavaScript 接口。如果您选择这样做,它就像将自定义公共方法添加到元素的原型一样简单。通过这些,您可以访问 Shadow DOM 的内部结构(参见此处的第三个示例)。

但是,您可以公开 CSS 的钩子以访问 Shadow DOM 的内部,而无需使用自定义元素。有两种方法可以做到这一点:

  1. 伪元素
  2. CSS 变量

伪元素

Chrome 和 Firefox 通过特殊的伪元素将其 Shadow DOM 的某些部分暴露给 CSS。这是您的输入示例,其中添加了 CSS 规则,该规则仅通过使用 Chrome 提供的伪元素date应用于日期字段的数字部分。-webkit-datetime-edit

这是可用的 WebKit 伪元素的部分列表。您也可以Show Shadow DOM在 DevTools 中启用该选项并查找名为pseudo.

组件作者还可以创建他们自己的伪元素来公开他们的 Shadow DOM 的一部分(参见此处的第二个示例)。

CSS 变量

更好的方法是使用 CSS 变量,您可以在 Chrome 中启用Enable experimental WebKit featuresabout:flags。然后查看这个小提琴,它使用 CSS 变量与 Shadow DOM 进行通信,它应该为它的“主题”使用什么颜色。

于 2013-05-20T18:47:35.253 回答
19

现在(2016 年),您可以使用Shadow DOM 根目录上的方法访问开放的用户创建的影子 DOM 元素(但没有用户代理创建的影子 DOM!) :querySelector

<body>
    <div id="container"></div>
    <script>
        //Shadow Root
        ̶v̶a̶r̶ ̶r̶o̶o̶t̶ ̶=̶ ̶c̶o̶n̶t̶a̶i̶n̶e̶r̶.̶c̶r̶e̶a̶t̶e̶S̶h̶a̶d̶o̶w̶R̶o̶o̶t̶(̶)̶
        //new syntax:
        var root = container.attachShadow( { mode: "open" } )

        //Inside element
        var span = document.createElement( "span" )
        span.textContent = "i'm inside the Shadow DOM"
        span.id = "inside"
        root.appendChild( span )

        //Access inside element
        console.log( container.shadowRoot.querySelector( "#inside" ) )
    </script>
</body>

//Shadow Root
var root = container.createShadowRoot()

//Inside element
var span = document.createElement( "span" )
span.textContent = "i'm inside the Shadow DOM"
span.id = "inside"
root.appendChild( span )

//Access inside element
function get() 
{
  alert( container.shadowRoot.querySelector( "#inside" ).id )
}
<!DOCTYPE html>
<html>
<head>
    <title></title>
	<meta charset="utf-8" />
</head>
<body>
	<div id="container"></div>
    <button onclick="get()">Get</button>
	<script>
	</script>
</body>
</html>

于 2016-01-08T13:44:49.303 回答
4

您无法从 Shadow DOM 之外的脚本访问 Shadow DOM 的内容。封装是 Shadow DOM 的目的。

于 2013-05-20T00:15:10.210 回答
4

是的。你只需要调用 .root 或 .shadowRoot 。这是一个例子,

document.getElementById('itemId').root 

如果没有父 dom 元素上的 innerText 或 innerHTML,您将无法获得 shadow dom 元素。

于 2018-12-05T05:31:27.560 回答