如何从模板中用 Shadow DOM 装饰的 HTML 元素中删除影子根?

新手上路,请多包涵

我正在探索 Chrome Canary (33.0.1712.3) 中的导入、模板、影子 DOM 和自定义元素。在网格布局中,我有一个特定的内容元素(显示区域),它将显示不同的 Web 组件或从文件导入的克隆轻型 DOM 片段。

但是,一旦添加了影子 DOM,我就无法重新显示普通的 HTML DOM,因为我不知道如何删除影子根。一旦创建,shadow root 就会保留并干扰普通 DOM 的渲染。 (我看过各种 W3C 规范,例如 Web 组件介绍、shadow DOM、模板、Bidelman 关于 HTML5 Rocks 的文章等)我在下面的一个简单示例中隔离了这个问题:

单击“显示普通旧 div”;点击“显示阴影模板”;单击“显示普通旧 div”。每次点击后在 devtools 中检查。第三次单击后,按钮下方没有输出,我在 devtools 中看到:

 <div id="content">
  #document-fragment
  <div id="plaindiv">Plain old div</div>
</div>

我需要添加什么到 removeShadow() 来删除影子根并将内容元素完全重置为其初始状态?

删除_shadows.html

 <!DOCTYPE html>
<html lang="en">

<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>

  <template id="shadowedTemplateComponent">
    <style>
      div { background: lightgray; }
      #t { color: red; }
    </style>

    <div id="t">template</div>

    <script>console.log("Activated the shadowed template component.");</script>
  </template>

  <template id="plainDiv">
    <div id="plaindiv">Plain old div</div>
  </template>
</head>

<body>
<div>
  <input type="button" value="show plain old div" onclick="showPlainOldDiv()"/>
  <input type="button" value="show shadowed template" onclick="showShadowTemplate()"/>
  <div id="content"></div>
</div>

<script>
  function removeChildren(elt) {
    console.log('removing children: %s', elt);
    while (elt.firstChild) {
      elt.removeChild(elt.firstChild);
    }
  }
  function removeShadow(elt) {
    if (elt.shadowRoot) {
      console.log('removing shadow: %s', elt);
      removeChildren(elt.shadowRoot); // Leaves the shadow root property.
      // elt.shadowRoot = null; doesn't work
      // delete elt.shadowRoot; doesn't work
      // What goes here to delete the shadow root (#document-fragment in devtools)?
    }
  }

  function showPlainOldDiv() {
    console.log('adding a plain old div');
    var host = document.querySelector('#content');
    removeChildren(host);
    removeShadow(host);
    var template = document.querySelector('#plainDiv');
    host.appendChild(template.content.cloneNode(true));
  }

  function showShadowTemplate() {
    console.log('adding shadowed template component');
    var host = document.querySelector('#content');
    removeChildren(host);
    removeShadow(host);
    var template = document.querySelector('#shadowedTemplateComponent');
    var root = host.shadowRoot || host.webkitCreateShadowRoot();
    root.appendChild(template.content.cloneNode(true));
  }
</script>
</body>
</html>

原文由 wjohnson 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 828
2 个回答

添加影子根后,您将无法删除它。但是,您可以将其替换为更新的。

如此处所述, http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-301/ ,最新的影子根“获胜”并成为呈现的根。

您可以使用仅包含 <content> 伪元素的新影子根替换您的影子根,以将所有内容从 light DOM 插入回 shadow DOM。到那时,据我所知,它在功能上等同于根本没有影子 DOM。

原文由 rmcclellan 发布,翻译遵循 CC BY-SA 3.0 许可协议

Shadow DOM 的规范从 v0 移到了 v1。

其中一个变化是在 v1 中无法在其自身上创建影子根并且宿主元素可能只包含一个影子根。

因此,用新的空白影子根替换影子根的答案似乎不再有效。

解决方案路径

  • 如果 host 元素自身(在您的示例中为 div )除了持有 Shadow DOM 之外没有特殊价值,可以将 host 元素替换为整个元素
  • 如果仍然喜欢保留 host ,用 e.shadowRoot.innerHTML = '' 之类的东西清除 Shadow DOM 可能就足够了

原文由 GullerYA 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题