当元素通过其ID直接访问而不是getElementById时,扩展问题

问题描述 投票:0回答:1

即使不建议这样做,JavaScript仍允许您按元素的ID访问元素,而无需使用getElementById。

<iframe id="myframe" />
<script>
    var i = window.myframe;
</script>

这为扩展程序带来了问题,这些扩展程序在访问元素本身时需要访问它们。执行此操作的方法是在原型上为getElementById调用Object.defineProperty(),以便在调用该元素时可以访问该元素。但是,当直接引用元素时,因此不会调用getElementById,它们是扩展的盲点。我尝试了以下方法,但是没有任何运气。

  • 迭代内容脚本中的DOM似乎不起作用,因为尚未加载完整的DOM。
  • 无法设置'DOMContentLoaded'的侦听器,因为到那时页面的脚本已经运行并且可能访问了元素。
  • 尝试将脚本插入页面上的第一个脚本之前,但再次插入,实际上还不存在。

有人知道这样引用元素时JavaScript使用的内部机制吗?我很好奇是否在内部调用了另一个函数,它可能像getElementById一样被钩住。还是有一种方法可以确保在DOM加载之后但在页面脚本运行之前运行内容脚本代码?

javascript google-chrome-extension firefox-addon
1个回答
0
投票

或者是否有一种方法可以确保在加载DOM之后但在页面脚本运行之前运行内容脚本代码?

问题是页面脚本可以运行之前,DOM已完全加载。例如,下面:

<div id="foo"></div>
<script>
foo.textContent = 'foo';
</script>
<div id="bar"></div>

脚本将运行之前创建bar元素(在加载DOM之前)。

可以使用[id]查找DOM中当前具有ID的所有元素,并且可以通过简单地重新分配属性来在窗口上重新分配这些属性-或者,如果要在检索元素时运行代码,则可以可以使用Object.defineProperty将其转换为吸气剂。您需要能够在脚本加载之前找到ID并重新分配ID,这可以通过子树MutationObserver完成-在插入<script>之前,在DOM中的[id]上进行迭代,然后重新分配它们:] >

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>

它可以从抛光中受益,但这是一般的想法。

© www.soinside.com 2019 - 2024. All rights reserved.