如何使用 Safari App Extensions 将 iframe 正确注入 DOM?

How to properly inject an iframe to the DOM with Safari App Extensions?

我正在使用 Safari 应用程序扩展将我的 WebExtension 移植到 Safari。

我的扩展是 DOM 中的 iframe 注入,所以我想将类似此注入脚本的东西加载为 SFSafariContentScript

document.addEventListener('DOMContentLoaded', function(e) {
    var newElement = document.createElement("script");
    newElement.src = safari.extension.baseURI + "bundle.js";
    document.body.insertBefore(newElement, document.body.firstChild);
});

问题是 DOMContentLoaded 事件似乎在注入我的 iframe 时再次触发,导致无限循环。

此行为似乎不同于您对具有两个文件 index.htmlindex.js 的简单注入脚本所期望的行为,该脚本按预期工作。

───────┬───────────────────────────────────────────────────────────────────
       │ File: index.html
───────┼───────────────────────────────────────────────────────────────────
   1   │ <html>
   2   │   <head>...</head>
   3   │   <body><div>...</div></body>
   4   │   <script src="index.js"></script>
   5   │ </html>
───────┴───────────────────────────────────────────────────────────────────
───────┬───────────────────────────────────────────────────────────────────
       │ File: index.js
───────┼───────────────────────────────────────────────────────────────────
   1   │ document.addEventListener('DOMContentLoaded', function(e) {
   2   │   var newElement = document.createElement('script');
   3   │   newElement.src = './bundle.js';
   4   │   document.body.insertBefore(newElement, document.body.firstChild);
   5   │ });
───────┴───────────────────────────────────────────────────────────────────

如果我在我的 Safari 应用程序扩展中用几秒钟的 setTimeout 替换 addEventListener,我的扩展被正确注入并且运行良好但选择任意时间注入 iframe 感觉很脏对我来说。

如何使用 Safari 应用程序扩展将 iframe 正确注入 DOM?

在这种情况下包装我的代码可以达到注入脚本部分 Apple's documentation 的效果。

if (window.top === window) {
    // The parent frame is the top-level frame, not an iframe.
    // All non-iframe code goes before the closing brace.
    document.addEventListener('DOMContentLoaded', function(e) {
        var newElement = document.createElement("script");
        newElement.src = safari.extension.baseURI + "bundle.js";
        document.body.insertBefore(newElement, document.body.firstChild);
    });
}