直接通过 id 而不是 getElementById 访问元素时的扩展问题
Extension issue when elements are accessed directly by their id, not getElementById
尽管不推荐,JavaScript 允许您通过元素的 ID 访问元素,而无需使用 getElementById。
<iframe id="myframe" />
<script>
var i = window.myframe;
</script>
这给需要在访问所述元素时访问所述元素的扩展带来了问题。这样做的方法是在 getElementById 的原型上调用 Object.defineProperty() ,这样当它被调用时,您就可以访问该元素。但是,当直接引用一个元素时,getElementById 不会因此被调用,它们是扩展的盲点。我尝试了以下但没有任何运气。
- 迭代内容脚本中的 DOM 似乎不起作用,因为尚未加载完整的 DOM。
- 为 'DOMContentLoaded' 设置侦听器不是一个选项,因为到那时页面的脚本已经 运行 并可能访问元素。
- 正在尝试在页面上的第一个脚本之前插入脚本,但同样,此时还没有真正存在的东西。
有人知道 JavaScript 像这样引用元素时使用的内部机制吗?我很好奇它是否在内部调用了另一个可能像 getElementById 一样被挂钩的函数。或者有没有办法确保内容脚本代码在 DOM 加载之后但在页面脚本 运行s 之前是 运行?
Or is there a way to ensure the content script code is run after the DOM loads but before the page scripts runs?
一个问题是页面脚本可以 运行 在 DOM 完全加载之前。例如,下面:
<div id="foo"></div>
<script>
foo.textContent = 'foo';
</script>
<div id="bar"></div>
脚本将 运行 在 创建 bar
元素之前(在加载 DOM 之前)。
可以使用 [id]
查找当前在 DOM 中具有 ID 的所有元素,并且可以通过简单地重新分配 属性 来重新分配 window 上的这些属性] - 或者,如果您想在检索元素时 运行 编码,您可以使用 Object.defineProperty
将其变成 getter。您需要能够在脚本加载之前找到 ID 并重新分配它们,这可以通过子树 MutationObserver 来完成 - 在插入 <script>
之前,迭代 [=37] 中的 [id]
s =],并重新分配它们:
console.log('(empty JS block inserted by Stack Snippet editor)');
<script>
new MutationObserver((mutations) => {
// Check to see if a script was inserted
if (mutations.every(
mutation => [...mutation.addedNodes].every(
addedNode => addedNode.tagName !== 'SCRIPT'
)
)) {
// No scripts inserted
return;
}
console.log('id reassignment running');
for (const elm of document.querySelectorAll('[id]')) {
Object.defineProperty(window, elm.id, {
get() {
console.log('Custom code running');
return elm;
},
configurable: true
});
}
})
.observe(document.body, { childList: true, subtree: true });
</script>
<div id="foo"></div>
<script>
console.log('Lower script about to reference foo');
foo.textContent = 'foo';
console.log('Lower script has finished referencing foo');
</script>
<div id="bar"></div>
它可以从一些润色中获益,但这是一般的想法。
尽管不推荐,JavaScript 允许您通过元素的 ID 访问元素,而无需使用 getElementById。
<iframe id="myframe" />
<script>
var i = window.myframe;
</script>
这给需要在访问所述元素时访问所述元素的扩展带来了问题。这样做的方法是在 getElementById 的原型上调用 Object.defineProperty() ,这样当它被调用时,您就可以访问该元素。但是,当直接引用一个元素时,getElementById 不会因此被调用,它们是扩展的盲点。我尝试了以下但没有任何运气。
- 迭代内容脚本中的 DOM 似乎不起作用,因为尚未加载完整的 DOM。
- 为 'DOMContentLoaded' 设置侦听器不是一个选项,因为到那时页面的脚本已经 运行 并可能访问元素。
- 正在尝试在页面上的第一个脚本之前插入脚本,但同样,此时还没有真正存在的东西。
有人知道 JavaScript 像这样引用元素时使用的内部机制吗?我很好奇它是否在内部调用了另一个可能像 getElementById 一样被挂钩的函数。或者有没有办法确保内容脚本代码在 DOM 加载之后但在页面脚本 运行s 之前是 运行?
Or is there a way to ensure the content script code is run after the DOM loads but before the page scripts runs?
一个问题是页面脚本可以 运行 在 DOM 完全加载之前。例如,下面:
<div id="foo"></div>
<script>
foo.textContent = 'foo';
</script>
<div id="bar"></div>
脚本将 运行 在 创建 bar
元素之前(在加载 DOM 之前)。
可以使用 [id]
查找当前在 DOM 中具有 ID 的所有元素,并且可以通过简单地重新分配 属性 来重新分配 window 上的这些属性] - 或者,如果您想在检索元素时 运行 编码,您可以使用 Object.defineProperty
将其变成 getter。您需要能够在脚本加载之前找到 ID 并重新分配它们,这可以通过子树 MutationObserver 来完成 - 在插入 <script>
之前,迭代 [=37] 中的 [id]
s =],并重新分配它们:
console.log('(empty JS block inserted by Stack Snippet editor)');
<script>
new MutationObserver((mutations) => {
// Check to see if a script was inserted
if (mutations.every(
mutation => [...mutation.addedNodes].every(
addedNode => addedNode.tagName !== 'SCRIPT'
)
)) {
// No scripts inserted
return;
}
console.log('id reassignment running');
for (const elm of document.querySelectorAll('[id]')) {
Object.defineProperty(window, elm.id, {
get() {
console.log('Custom code running');
return elm;
},
configurable: true
});
}
})
.observe(document.body, { childList: true, subtree: true });
</script>
<div id="foo"></div>
<script>
console.log('Lower script about to reference foo');
foo.textContent = 'foo';
console.log('Lower script has finished referencing foo');
</script>
<div id="bar"></div>
它可以从一些润色中获益,但这是一般的想法。