直接通过 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 不会因此被调用,它们是扩展的盲点。我尝试了以下但没有任何运气。

有人知道 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>

它可以从一些润色中获益,但这是一般的想法。