使用原生JavaScript遍历所有同域iframe并修改其CSS样式的问题
修复遍历同域iframe修改样式的循环问题
你遇到的问题是闭包作用域导致的循环变量共享——原来的代码用var声明循环变量i,它是函数级作用域,当iframe的load事件触发时,循环已经执行完毕,i的值已经变成了iframes.length,自然找不到对应的iframe。下面给你几种可行的修复方案:
方案1:用let替代var(ES6+简洁方案)
let是块级作用域变量,每次循环都会创建一个独立的i绑定到当前迭代,这样事件处理函数就能捕获到正确的索引:
<script> const iframes = document.getElementsByTagName("iframe"); for (let i = 0; i < iframes.length; i++) { iframes[i].addEventListener("load", function() { const styleNode = document.createElement('style'); styleNode.textContent = 'body { background: red; }'; window.frames[i].document.head.appendChild(styleNode); }); } </script>
方案2:用this直接访问当前iframe(最直观方案)
在load事件的回调函数里,this指向触发事件的iframe元素,我们可以直接通过this.contentDocument访问它的文档对象,完全不需要依赖循环变量:
<script> const iframes = document.getElementsByTagName("iframe"); for (var i = 0; i < iframes.length; i++) { iframes[i].addEventListener("load", function() { const styleNode = document.createElement('style'); styleNode.textContent = 'body { background: red; }'; this.contentDocument.head.appendChild(styleNode); }); } </script>
这种方法更清晰,也避免了作用域相关的坑,推荐使用。
方案3:立即执行函数(IIFE)兼容旧浏览器
如果需要兼容不支持ES6的旧浏览器,可以用立即执行函数把每次循环的i值捕获到独立的作用域里:
<script> var iframes = document.getElementsByTagName("iframe"); for (var i = 0; i < iframes.length; i++) { (function(currentIndex) { iframes[currentIndex].addEventListener("load", function() { var styleNode = document.createElement('style'); styleNode.appendChild(document.createTextNode('body { background: red; }')); window.frames[currentIndex].document.head.appendChild(styleNode); }); })(i); } </script>
补充说明
因为你的iframe都是同域的,所以可以直接访问它们的contentDocument或document对象,不会遇到跨域安全限制。如果是跨域iframe,这种方法就不适用了,浏览器会阻止跨域的DOM操作。
内容的提问来源于stack exchange,提问作者Madamadam
相关产品推荐
相关产品推荐

