使用纯 javascript 遍历所有 iframe 并更改它们的 CSS 样式

Looping through all iframes with plain javascript and altering their CSS styles

我有一个父 HTML 文件,其中包含托管在同一域中的多个 iframe。现在我想遍历所有 iframe 并通过向它们添加 CSS 带有纯 javascript 样式来更改它们的视觉外观:

<!DOCTYPE html>
<html>
    
    <head>
        <title>
        Altering CSS in iframe
        </title>
    </head>
    
    <body>
        <h1>Parent HTML</h1>
        <iframe id="frameID1" name="frameID1" srcdoc="
        <!DOCTYPE html>
        <html>
            <head>
                <meta charset=&quot;utf-8&quot;>
            </head>
            <body>
                <p>This is my iframe #1</p>
            </body>
        </html>
        "></iframe>

        <iframe id="frameID2" name="frameID2" srcdoc="
        <!DOCTYPE html>
        <html>
            <head>
                <meta charset=&quot;utf-8&quot;>
            </head>
            <body>
                <p>This is my iframe #2</p>
            </body>
        </html>
        "></iframe>

        <iframe id="frameID3" name="frameID3" srcdoc="
        <!DOCTYPE html>
        <html>
            <head>
                <meta charset=&quot;utf-8&quot;>
            </head>
            <body>
                <p>This is my iframe #3</p>
            </body>
        </html>
        "></iframe>

        <script>
            var iframes = document.getElementsByTagName("iframe");
            for (var i = 0; i < iframes.length; i++) {
                iframes.item(i).addEventListener("load", function() {
                var node = document.createElement('style');
                node.appendChild(document.createTextNode('body { background: red; }'));     
                window.frames[i].document.head.appendChild(node)
            })
            }
        </script>
    </body>
</html>

但是 javascript 代码中的循环不起作用。我已经设置了一个 fiddle,其中我将 window.frames[i].document.head.appendChild(node) 更改为 window.frames[i-2].document.head.appendChild(node) 这显示了一种效果,但仅更改了一个 iframe 中的样式,而不是所有 iframe 中的样式: https://jsfiddle.net/5a8bdynm/

我必须更改什么才能影响所有 iframe?

您正在使用 varfor 循环中定义索引 i。所以,你的索引是一个全局变量。

但是您的事件(加载)是异步的 (1),因此当第一个 iframe 加载时,索引的值已经是 3。在这种情况下,window.frames[i] 将始终引用 window.frames[3] 甚至不存在。

如果将 var 替换为 let,每个循环周期将收到其自己单独的索引值,并且 window.frames[i] 将引用正确的 iframe。

const iframes = document.getElementsByTagName("iframe")
for (let i = 0; i < iframes.length; i++) { // your code}

一般来说,您应该避免使用 var。 首选 letconst 作为最佳实践。

(1) 编辑: 顺便说一句,加载事件的异步性质在这种情况下并不相关,因为代码是事件处理程序的一部分;所以,无论事件是什么,它都会在循环结束后执行(然后,在全局索引变量的值为 3 后)