有没有办法阻止影子 dom 内的 javascript 访问影子外的 DOM?

Is there a way to prevent javascript within a shadow dom from accessing the DOM outside of it?

所以如果我有:

js可以改变component_test_div

中的文字

我可以阻止吗?

脚本不受影子保护DOM

Shadow DOM 仅保护 CSS 泄漏或干扰 shadowRoot 的内容。它不会为 JavaScript.

创建新的命名空间

在这段代码中,我在影子根目录中有一些 JS:

class MyEl extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({mode:'open'});
    let s = document.createElement('script');
    s.textContent = "function dog() { console.log('Bark, Bark'); }";
    this.shadowRoot.appendChild(s);
  }
}

customElements.define('my-el', MyEl);

setTimeout(()=>dog(), 2000);
<my-el></my-el>

2 秒后我们调用函数 dog() 并且它起作用了。那是因为,即使这段代码被放置在一个shadowRoot中,它仍然在全局范围内执行。

鉴于无法在 Web 组件中隔离您的 JavaScript,您需要记住它可供其范围内的任何人使用。

如果将代码放在 IIFE 中,则可以防止外部调入。但是仍然没有办法阻止内部调出或操纵作用域外的东西。


确定元素是否在阴影中的替代方法DOM

作为@Angel Politis 回答的替代方法,有一种更简单的方法可以确定某个元素是否在某人的 shadowRoot 中:

function isInShadowDOM(el) {
  let ret = false;

  if (el.getRootNode) {
    doc = el.getRootNode();
    ret = (doc !== document);
  }

  return ret;
}

您可以对您想要保护的元素使用 封闭阴影 DOM

component_test_div.attachShadow( { mode: "closed" } )
                  .innerHTML = "READ-ONLY"
                  
app_list.attachShadow( { mode: "closed" } )
        .appendChild( script.content )
<div id="component_test_div"></div>

<div id="app_list"></div>

<template id="script">
    <script>
        console.info( "shadowRoot is", component_test_div.shadowRoot )
        component_test_div.textContent = "SHADOWED BY SHADOW DOM"
    </script>
</template>

影子根的内容将替换任何初始或更改的文本。 closed 属性 将阻止其他脚本访问 shadow root。