重新加载一个IFRAME而不添加到历史记录中。

75
我正在更改一个IFRAME的src以重新加载它,它能正常工作并在HTML加载时触发onload事件。
但是它会添加一个历史记录,而我不希望这样。有没有办法重新加载IFRAME而不影响历史记录?

7
我猜问题出在返回按钮会在回到上一页之前先在 iframe 中循环。 - Darryl Hein
3
不管它做了什么,我都不想添加到历史记录中,或者有没有办法删除最新的历史记录条目? - Robin Rodricks
11个回答

80

如果使用replace()的话,只有针对您自己域名的iframe才是可选项。 在远程站点上(例如:Twitter按钮)无法正常工作,并且需要一些特定于浏览器的知识来可靠地访问子窗口。

相反,只需删除iframe元素并在同一位置构建一个新元素。 只有在将src属性修改为DOM中的元素之后才会创建历史记录项目,因此请务必在附加之前设置它。

编辑:JDandChips正确指出,可以从DOM中删除,修改和重新附加。 不需要构建全新的元素。


6
虽然这个答案比被接受的答案新了2年,但它是更改iframe URL/src而不会添加到浏览器历史记录的正确方法。任何其他组合的window.frames[frameName].location和/或history.replaceState出于安全原因都无法在iframe中工作。即使在同一域内(正如我刚发现的那样)。 - Samuel Clay
这是我尝试过的最好的可行答案。解决了我的问题。 - pawelglow
解决方案就是这个!我需要创建iframe,这样历史记录才能保持完整。 - roq
很好的答案。我试图使用iframe和angular添加vimeo嵌入式视频,就像这样:<div ng-repeat="item in ct.items"><iframe src="{{item.url}}"></iframe></div>。发生的情况是,在angular设置iframe url之前,html尝试使用错误的url加载iframe,如{{item.url}},结果是iframe的src被更改,导致浏览器历史记录问题!解决方案是稍后使用jquery创建iframe,在angular渲染所有内容后。 - Fábio Magagnin
如果在 iframe 内部更改 URL(例如,如果用户单击或 J.S. 重定向到 iframe 内的第二个页面),是否也会出现此问题?我不通过 DOM 直接更改 iframe src。例如:我在我的 SPA 中嵌入了一个 AdobeEsign 页面,该页面在同一 iframe 中重定向到一个感谢页面(然后感谢页面发送 windows.postmessage 回到我的主框架,以便我可以关闭 iframe)...但是在此时单击浏览器的返回按钮似乎想要“离开页面”(当用户离开 SPA 时,我的 window.beforeunload 事件会触发)。 - armyofda12mnkeys

38

你可以使用 JavaScript 的 location.replace 方法:

window.location.replace('...html');

用提供的URL替换当前文档。与assign()方法的区别在于,在使用replace()方法后,当前页面不会保存在会话历史记录中,这意味着用户无法使用“后退”按钮导航到它。


3
这不会影响页面本身吗?我只想重新加载IFRAME,并且我无法控制加载的文档内运行的脚本。 - Robin Rodricks
7
只需将“window”替换为您的iframe的引用即可。 - Ishmael
3
为什么这不是那么简单?var ifr = document.getElementById("iframeId"); ifr.location.replace(ifr.src);翻译后的内容: 为什么情况并不如此简单?var ifr = document.getElementById(“iframeId”);ifr.location.replace(ifr.src); - epascarello
2
尝试使用 window.frames['frame_name'].location - ChrisD
19
你也可以使用iframe.contentWindow.location.replace(href); - Kyle
显示剩余3条评论

26

就像 Greg 在上面所说的那样,.replace() 函数可以实现这个功能。我好像无法回复他的答案,但关键是引用 iFrame 的 contentWindow 属性。

var ifr = document.getElementById("iframeId");
ifr.contentWindow.location.replace("newLocation.html"); 

我刚刚了解到我需要更多的声望才能在回答中进行评论。


15

另一种重新创建 iframe 的替代方法是从 DOM 中移除 iframe,更改 src 然后重新添加它。

在很多方面,这与 replace() 建议类似,但是当我尝试使用 History.js 并手动管理状态时,遇到了一些问题。

var container = iframe.parent();

iframe.remove();
iframe.attr('src', 'about:blank');

container.append(iframe);

我真的很喜欢这个:它比创建新的iframe要容易得多,因为你不需要将所有属性复制到新的iframe中(id、大小、样式类等)。 - Legolas
太好了。这个解决方案对我在Bootstrap模态窗口中加载iframe内容的情况下起作用。当模态关闭时,使用回调函数将其删除并重新添加。修复了后退按钮问题。 $(modal).one('hidden.bs.modal', function() { $(modal_iframe).attr('src', 'about:blank').addClass('d-none'); var modalParent = $(modal_iframe).parent(); $(modal_iframe).remove(); $(modalParent).append($(modal_iframe)); }); - drew010

10

非常同意@JBE的回答,这对我在Angular2中避免iframe src更改触发历史记录更新方面帮助很大。 - N.Schipper
这对我不起作用。我在Chrome中。即使销毁iframe并将其替换为对象,仍会导致该死的浏览器历史记录状态(这是没有意义的,因为被摧毁的对象永远不会恢复其内容)。Grrrrrrrrr. - trusktr

5

尝试使用此函数将旧的iframe替换为从旧的iframe复制的新的iframe:

function setIFrameSrc(idFrame, url) {
    var originalFrame = document.getElementById(idFrame);
    var newFrame = document.createElement("iframe");
    newFrame.id = originalFrame.getAttribute("id");
    newFrame.width = originalFrame.getAttribute("width");
    newFrame.height = originalFrame.getAttribute("height");
    newFrame.src = url;    
    var parent = originalFrame.parentNode;
    parent.replaceChild(newFrame, originalFrame);
}

可以像这样使用:

setIFrameSrc("idframe", "test.html");

这种方式不会将iframe的URL添加到浏览器历史记录中。

1
这很方便。谢谢! - André

1
使用replace方法可以绕过将iframe的URL添加到历史记录中的操作:
HTML:
<iframe id="myIframe" width="100%" height="400" src="#"></iframe>

JavaScript:

var ifr = document.getElementById('mIframe')
if (ifr) {
  ifr.contentWindow.location.replace('http://www.blabla.com')
}

replace 函数接收的字符串/URL 是什么? - 2540625

1

JDandChips的答案对我在跨域iframe(youtube)上起作用,这是使用vanilla JS(没有JQuery)的代码:

const container = iframe.parentElement;

container.removeChild(iframe);

iframe.setAttribute('src', 'about:blank');

container.appendChild(iframe);

0

最简单和加载最快的解决方案
使用window.location.replace在加载页面或框架时不更新历史记录。

对于链接,它看起来像这样:

<a href="#" onclick="YourTarget.location.replace ('http://www.YourPage.com');">
The targeted Link</a>

或者

<a href="javascript:YourTarget.location.replace ('http://www.YourPage.com');">
The targeted Link</a>



但是,如果你希望它不是从链接中触发,而是在加载框架时自动触发,则应该在iframe文件的body部分中放置以下内容:

onload="window.location.replace ('http://www.YourPage.com');"


如果由于某些原因 onload 在 iframe 中无法加载,则在语法中将目标框架名称替换为 window,如下所示:
onload="YourTarget.location.replace ('http://www.YourPage.com');"



注意:对于此脚本,所有的onclickonmouseoveronmouseoutonloadhref="javascript:"都可以正常工作。


0
@JDandChips的回答很好,但语法应该从parent()更新为parentElement:

var container = iframe.parentElement;

iframe.remove();
iframe.attr('src', 'about:blank');

container.append(iframe);

欢迎来到 StackOverflow!如果一个回答已经基本正确,只需要些微的修改,你应该建议编辑该回答,而不是自己发布一个新的。如果你的建议被采纳,它会让你获得徽章 :) - Das_Geek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接