您可以对要保护的元素使用封闭的 Shadow 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>
影子根的内容将替换任何初始或更改的文本。 close 属性将阻止其他脚本访问影子根目录。
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中,它仍然在全局范围内执行。
鉴于无法将 JavaScript 隔离在 Web 组件中,您需要记住它可供其范围内的任何人使用。
如果将代码放在 IIFE 中,则可以阻止外部调用。但是仍然无法阻止内部调用或操作范围之外的事物。
作为 @Angel Politis 答案的替代方法,有一种更简单的方法可以确定某个元素是否在某人的 ShadowRoot 中:
function isInShadowDOM(el) {
let ret = false;
if (el.getRootNode) {
doc = el.getRootNode();
ret = (doc !== document);
}
return ret;
}