处理iframe内的历史导航

时间:2013-10-18 14:40:48

标签: javascript html5 iframe html5-history

我正在构建一个导航页面,显示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.onpopstatenull

最后,我尝试使用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

1 个答案:

答案 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>