为何首次for循环无法替换全部iframe?是否操作有误?
替换iframe时循环无法一次性替换全部元素的问题分析
问题现象
尝试用文本替换页面中的iframe元素时,执行三次循环才将所有7个iframe替换完成:
- 初始iframe数量:7
- 首次循环后剩余:3
- 第二次循环后剩余:1
- 第三次循环后剩余:0
示例代码
JavaScript代码
// once console.log(document.getElementsByTagName("iframe").length) for (let iframe of document.getElementsByTagName("iframe")) { iframe.replaceWith(`"${iframe.title}": ${iframe.src}`) } // twice console.log(document.getElementsByTagName("iframe").length) for (let iframe of document.getElementsByTagName("iframe")) { iframe.replaceWith(`"${iframe.title}": ${iframe.src}`) } // thrice console.log(document.getElementsByTagName("iframe").length) for (let iframe of document.getElementsByTagName("iframe")) { iframe.replaceWith(`"${iframe.title}": ${iframe.src}`) } console.log(document.getElementsByTagName("iframe").length)
HTML代码
<iframe width="560" height="315" src="https://www.youtube.com/embed/AW8OOp2undg?si=GSgNE9ERhGMkX_o4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe> <iframe width="560" height="315" src="https://www.youtube.com/embed/AW8OOp2undg?si=GSgNE9ERhGMkX_o4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe> <iframe width="560" height="315" src="https://www.youtube.com/embed/AW8OOp2undg?si=GSgNE9ERhGMkX_o4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe> <iframe width="560" height="315" src="https://www.youtube.com/embed/AW8OOp2undg?si=GSgNE9ERhGMkX_o4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe> <iframe width="560" height="315" src="https://www.youtube.com/embed/AW8OOp2undg?si=GSgNE9ERhGMkX_o4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe> <iframe width="560" height="315" src="https://www.youtube.com/embed/AW8OOp2undg?si=GSgNE9ERhGMkX_o4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe> <iframe width="560" height="315" src="https://www.youtube.com/embed/AW8OOp2undg?si=GSgNE9ERhGMkX_o4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>
问题原因
document.getElementsByTagName()返回的是动态的HTMLCollection对象,而非静态数组。这个集合会实时同步DOM的变化:当你在循环中用replaceWith()移除iframe元素时,集合的长度和元素索引会立即更新。
以初始7个iframe为例:
- 循环取第1个iframe(索引0)替换,集合长度变为6,原索引1的元素现在变成新的索引0
- 下一次循环取索引1的元素,相当于跳过了新的索引0元素,只处理了原索引2的元素
- 以此类推,每次循环仅处理一半左右的元素,导致需要多次循环才能处理完所有元素
解决方案
方案1:将动态集合转为静态数组
通过Array.from()或扩展运算符[...]把HTMLCollection转成静态数组,循环处理数组中的元素,不受DOM变化影响:
console.log(document.getElementsByTagName("iframe").length) // 转为静态数组 const iframes = Array.from(document.getElementsByTagName("iframe")); for (let iframe of iframes) { iframe.replaceWith(`"${iframe.title}": ${iframe.src}`) } console.log(document.getElementsByTagName("iframe").length) // 直接输出0
方案2:倒序循环处理
从最后一个元素开始倒序循环,即使前面的元素被移除,也不会影响后续要处理的元素索引:
console.log(document.getElementsByTagName("iframe").length) let iframes = document.getElementsByTagName("iframe"); // 从最后一个元素开始遍历 for (let i = iframes.length - 1; i >= 0; i--) { iframes[i].replaceWith(`"${iframes[i].title}": ${iframes[i].src}`) } console.log(document.getElementsByTagName("iframe").length) // 直接输出0
内容的提问来源于stack exchange,提问作者crxyz
相关产品推荐
相关产品推荐

