提问人:Mo W. 提问时间:3/24/2023 更新时间:3/24/2023 访问量:188
通过删除 '<script type=“text/plain”... />' 的 type 属性延迟脚本加载,在 firefox 上不起作用
Delayed script loading by removing type attribute of `<script type="text/plain"... />` not working on firefox
问:
我目前正在为 NextJS 开发自定义 cookie 同意解决方案,它似乎已经很好地与这种方法配合使用:
在同意后应该加载的 head 中的所有脚本都是这样实现的: 阻止浏览器加载和执行脚本。
同意后,我删除属性,克隆节点,删除原始节点并将其附加到 .否则,浏览器不会注意到更改。<script src="iSetSomeCookies.js" type="text/plain" data-cookieconsent />
type="text/plain"
type
<script>
<head>
这种方法适用于 Safari 和 Chrome,但不适用于 Firefox......
代码被执行,属性也被删除并添加为新的脚本节点。但是在网络选项卡中,脚本之后不会加载。type
有没有办法让 Firefox 重新解析 DOM 并加载脚本?
这是我的脚本中在给予 cookie 同意后执行的部分:
const blockedScripts = document.querySelectorAll<HTMLScriptElement>(
"script[data-cookieconsent]"
)
blockedScripts.forEach((script) => {
script.removeAttribute("type")
const copy = script.cloneNode()
document.head.insertBefore(copy, script)
script.remove()
})
我还尝试将类型更改为 and,但这仍然是相同的行为,Firefox似乎忽略了该更改。text/javascript
application/javascript
我已经看到了一些可用于在之后执行脚本的解决方案,但我不想使用 .eval(this.innerHtml)
eval
答:
有趣的是,Firefox不会运行克隆脚本引用的代码(我可以验证我用你的原始代码看到了这种行为)。我认为最简单的事情就是创建新节点,这似乎有效:
const blockedScripts = document.querySelectorAll("script[data-cookieconsent]");
for (const blocked of blockedScripts) {
const { parentElement, nextSibling } = blocked;
blocked.remove();
const script = document.createElement("script");
for (const attr of blocked.attributes) {
if (attr.name !== "type") {
script.setAttributeNode(attr.cloneNode());
}
}
parentElement.insertBefore(script, nextSibling);
}
该代码也不假定元素在元素中;相反,它使用原始元素的任何父元素。script
head
这里是 TypeScript (必须在克隆属性后添加,因为 的返回类型是 ,并添加一个 以说服 TypeScript 不是:as Attr
cloneNode
Node
if
parentElement
null
const blockedScripts = document.querySelectorAll<HTMLScriptElement>("script[data-cookieconsent]");
for (const blocked of blockedScripts) {
const { parentElement, nextSibling } = blocked;
if (!parentElement) { // Will never be true
throw new Error(`parentElement is null`);
}
blocked.remove();
const script = document.createElement("script");
for (const attr of blocked.attributes) {
if (attr.name !== "type") {
script.setAttributeNode(attr.cloneNode() as Attr);
}
}
parentElement.insertBefore(script, nextSibling);
}
您可能更喜欢 non-nullish 断言运算符 on;我真的不喜欢使用它,但这里有一个很好的论据:parentElement
const blockedScripts = document.querySelectorAll<HTMLScriptElement>("script[data-cookieconsent]");
for (const blocked of blockedScripts) {
const { parentElement, nextSibling } = blocked;
blocked.remove();
const script = document.createElement("script");
for (const attr of blocked.attributes) {
if (attr.name !== "type") {
script.setAttributeNode(attr.cloneNode() as Attr);
}
}
parentElement!.insertBefore(script, nextSibling);
}
评论
document.createElement("script")
script.cloneNode()
评论
<script>