【发布时间】:2020-11-11 13:52:10
【问题描述】:
我正在编写一些 HTML5 自定义元素,其中包含被转译的代码,以便它可以在页面上实际运行(图形代码、乳胶等),但我似乎找不到任何页面或 Stackoverlow 问题,这解释了是否以及如何加载脚本,使其范围限定为自定义元素本身。
相反,我所能找到的只是“根本没有信息”,所以我使用了有点傻的“将它插入文档头部,重写,以便它首先从全局寄存器中获取正确的元素”,这是超级肮脏的。我工作,但如果能够以一种运行它们的方式将脚本注入到影子 DOM 中,并且知道它们正在运行的确切元素是什么,那就更好了。
现在,代码(简化形式)如下所示:
import { uuid } from "./uuid.js";
import { Parser } from "./code-parser.js";
class MyElement extends HTMLElement {
constructor() {
super();
this.uid = uuid.v4();
window[this.uid] = this;
const jsCode = `
import { Base, API, ... } from "./lib.js";
class Example extends Base {
constructor() {
super(window[${this.uid}]);
delete window[${this.uid}];
}
${Parser.rewrite(this.textContent)}
}
new Example();
`;
const script = document.createElement(`script`);
script.type = `module`;
script.src = URL.createObjectURL(
new Blob([jsCode], {type: `text/javascript`})
);
this.attachShadow({ mode: 'open' }).append(script);
}
}
customElements.define(`my-element`, MyElement);
export { MyElement }
这当然有效,但通过(暂时)污染window 起作用。有没有办法将脚本元素附加到自定义元素或自定义元素的影子 DOM,以便在知道它正在运行的自定义元素或影子 DOM 的情况下执行?
编辑: 明确地说,这需要适用于使用依赖modules 的现代代码的脚本:任何import 语句仍然需要解决。另请注意,任何依赖于需要将unsafe-eval (6.1.11.3) 或unsafe-inline 添加到CSP script-src 指令的方法的东西都不能使用。
【问题讨论】:
-
为什么你认为你必须附加一个新的
-
因为实际脚本中的代码在任何地方都不存在。它是动态生成的。代码以字符串数据的形式存在,被重写为正确的 JS 并且 then 被注入。没有要导入的完整模块。
-
(我正在pomax.github.io/custom-graphics-element 上解决这个问题,以防您想了解与此问题无关但可能与您的兴趣相关的完整事件链)
-
对不起,我真的没有时间完全检查你的 repo,但是快速阅读它,你不需要在
-
不幸的是,我不能:理智的 CSP(例如,没有
unsafe-eval)不允许eval()、new Function()以及鲜为人知的字符串执行形式setTimeout和setInterval。此元素旨在在任意站点上运行,因此它仍然必须在具有正常 CSP 的站点上运行。现在需要unsafe-inline已经相当有问题了,我可能不得不将其切换为src="blob:..."注入。无论如何,最初的问题仍然存在:注入影子 DOM 的脚本如何获得对该影子 DOM 或影子 DOM 所有者的引用?
标签: html custom-element