我正在构建一个导航页面,显示iframe
内的一些内容。
要求是突出显示与当前加载的页面对应的导航链接。帧内容不受我的控制。当用户在浏览器中使用后退/前进按钮时,问题就开始了。
我们的想法是使用history.replaceState
将有关导航链接的信息与页面相关联,并在popstate
事件中恢复导航面板状态。当内容通过AJAX加载到应用程序中时,它完全适用于其他情况。
如果iframe
导航,则不会修改顶部窗口的history
对象,因此我应该使用contentWindow
,从而限制自己fto仅支持来自同一域的网页。
问题是我无法订阅该活动。以下代码不起作用:
$(window).on('popstate', function () { handleHistory('popstate@window'); });
$('#frame').on('popstate', function () { handleHistory('popstate@iframe'); });
$($('#frame')[0].contentWindow).on('popstate', function () { handleHistory('popstate@iframe.window'); });
$('#frame')[0].contentWindow.onpopstate = function () { handleHistory('popstate@iframe.window'); };
在后一种情况下,历史导航contentWindow.onpopstate
为null
。
最后,我尝试使用load
事件并且它有效,但是在它等待直到所有页面资源都被加载之前它会发生重大延迟。
$('#menu a').click(function() {
// ...
$('#frame').one('load', function() {
frameWindow.history.replaceState({ linkId: link.id },frameWindow.document.title, frameWindow.location.href);
});
// ...
});
$('#frame').load(function () { handleHistory('load@iframe'); });
我尝试的另一种方法是在计时器中轮询contentWindow.location.href
以便更早地做出反应。乍一看它运作良好,但后来我注意到有时候历史记录会从浏览器中消失(至少在Firefox中)。
var isLoading = false;
$('#menu a').click(function() {
// ...
isLoading = true;
$('#frame').one('load', function() { isLoading = false; });
(function poll () {
var frameWindow = getFrameWindow();
if (getFrameWindow().location.href == link.href) {
frameWindow.history.replaceState({ linkId: link.id },frameWindow.document.title, frameWindow.location.href);
} else {
setTimeout(poll, 100);
}
})();
// ...
});
setInterval(function () {
if (!isLoading) {
handleHistory('timer');
}
}, 100);
有没有其他好方法可以跟踪iframe
内的历史记录?可能我犯了一些错误?也许甚至有一种方法可以做到这一点,无论内容的域名?
以下是源代码和演示页面(添加了延迟以更好地说明脚本行为)
onload方法:src demo
计时器方法:src demo
答案 0 :(得分:0)
这确实不是一个令人满意的解决方案,但您可以在加载事件框架中检查历史堆栈的大小。
<html>
<body>
<iframe src="http://w3c.org" class="xssFrame"></iframe>
<p class="output"></p>
<script>
var size = window.history.length;
var tempSize = null
//document.querySelector(".xssFrame").unload = function(){} //might need to set this handler to force load event on back click
document.querySelector(".xssFrame").onload = function () {
var delta = size - window.history.length;
document.querySelector(".output").innerHTML = "parent history: " + size + " combined history: " + window.history.length + " go " + (delta-1).toString()
if(tempSize === window.history.length) {
document.querySelector(".output").innerHTML = "go now" + (delta).toString()
window.history.go(delta)
} else {
tempSize = window.history.length
}
}
</script>
</body>
</html>