3

我正在构建一个导航页面,该页面显示iframe. 要求是突出显示当前加载的页面对应的导航链接。框架内容不受我控制。当用户在其浏览器中使用后退/前进按钮时,问题就开始了。

这个想法是用来history.replaceState将有关导航链接的信息与页面相关联,并在popstate事件时恢复导航面板状态。当内容通过 AJAX 加载到应用程序中时,它在其他情况下工作得很好。

iframe导航的情况下,history顶部窗口的对象没有被修改,所以我应该使用contentWindow,从而限制我自己只支持来自同一域的页面。

问题是我无法订阅该活动。以下代码不起作用:

$(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 演示
计时器方法:src 演示

4

1 回答 1

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>
于 2015-02-20T06:13:30.353 回答