按下后退按钮2次后,history.js停止触发statechange事件

时间:2014-10-26 23:06:02

标签: javascript jquery iframe navbar history.js

我的一位客户有很多基于大量CMS(Wordpress,Drupal等)的网站。他想要一个通用目录,专业人员可以在其中注册和共享信息。它是“通用的”,因为它可以安装在任何网站上(根据网站的业务而拒绝)。

我在iframe中开发了它,因为它可以安装在任何CMS上,还有其他很好的理由这样做(CSS,SEO ...)。但是,由于iframe浏览对于导航栏是透明的,我需要做一些技巧,允许访问者复制/粘贴专业人士的网址,分享和收藏他们。我使用history.js来更新导航栏的URL,当直接访问iframe时,我将用户重定向到右侧“主要网站”的页面。

但点击“后退”按钮后出现问题。由于某些原因,第二次单击“返回”时未正确触发“statechange”事件。

我开发了一个演示,你可以看到my problem live here,你可以download it here

正如您在日志div中看到的,当您单击B和C时,您将获得:

Push: /a.html
Push: /b.html
statechange trigered
Push: /c.html
statechange trigered

如果你回去一次,你会得到:

statechange trigered
Pop: /b.html

如果你第二次回去,你会得到:

Push: /c.html
statechange trigered

而不是:

statechange trigered
Pop: /a.html

所以我的问题:

  

这里发生了什么?

main.html中

<iframe id="my-test" src="a.html" width="500" height="500"></iframe>

<div id="log"></div>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-browser/0.0.6/jquery.browser.min.js"></script>
<script src="history.js/scripts/bundled/html4+html5/jquery.history.js"></script>

<script type="text/javascript">

    var test_url = 'http://so.ocarina.fr/test';

    // used to avoid listening events trigered by the script itself
    var manual_state_change = true;

    // used to avoid pushing the previous page
    var is_back = false;

    $(document).ready(function () {
        $('#my-test').load(function () {

            // when iframe has loaded, we replace the navbar's url by
            // the one from iframe's source.

            if (!window.is_back) {
                window.manual_state_change = false;

                var History = window.History;
                if (History.enabled) {

                    var url = $('#my-test').get(0).contentWindow.location.href;
                    if (url.indexOf('blank') > 0) {
                        return;
                    }
                    if (url.indexOf('test') > 0) {
                        url = url.substring(url.indexOf('test') + 4);
                        if (url.length === 0) {
                            url = '/';
                        }
                    }

                    $('#log').append('Push: ' + url + '<br/>');

                    var title = $("#my-test").contents().find("title").html();
                    document.title = title;
                    History.pushState({url: decodeURIComponent(url + '')}, title, window.test_url + decodeURIComponent(url + ''));

                    window.manual_state_change = true;
                }
            }
            window.is_back = false;

        }).trigger('load'); // triggered once to replace main.html by a.html

        var History = window.History;
        if (History.enabled) {
            History.Adapter.bind(window, 'statechange', function () {

                // if user clicks back, we should change the iframe's location
                // to the backward url from history stack.

                $('#log').append('statechange trigered <br/>');

                if (window.manual_state_change === true) {
                    window.manual_state_change = false;
                    var state = History.getState();
                    var url = state.data.url;
                    $('#log').append('Pop: ' + url + '<br/>');
                    window.is_back = true;
                    $('#my-test').attr('src', window.test_url + url);
                    $('#my-test')[0].contentWindow.location = window.test_url + url;
                    window.manual_state_change = true;
                }

            });
        }

    });

</script>

a.html

<title>Test A</title>

<script type="text/javascript">
    if (top.location === self.location) {
        window.location = 'main.html';
    }
</script>

<div id="content">

    <p>This is test A</p>

    <a href="b.html">Go to test B</a>

</div>

b.html

<title>Test B</title>

<script type="text/javascript">
    if (top.location === self.location) {
        window.location = 'main.html';
    }
</script>

<div id="content">

    <p>This is test B</p>

    <a href="c.html">Go to test C</a>

</div>

c.html

<title>Test C</title>

<script type="text/javascript">
    if (top.location === self.location) {
        window.location = 'main.html';
    }
</script>

<div id="content">

    <p>This is test C</p>

    <p>Go back to A using your backward button...</p>

</div>

1 个答案:

答案 0 :(得分:0)

我终于发现了我的错误:点击我的iframe链接时,浏览器已经在历史记录中添加了一个条目,因此我不应该使用pushState添加条目,而只是替换使用replaceState的当前历史记录条目。

奖励:我们不需要处理状态转换,浏览器会像往常一样自然地做任何事情。酷!

参见工作演示here

我的代码变为:

<iframe id="my-test" src="a.html" width="500" height="500"></iframe>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-browser/0.0.6/jquery.browser.min.js"></script>
<script src="history.js/scripts/bundled/html4+html5/jquery.history.js"></script>

<script type="text/javascript">

  var test_url = 'http://so.ocarina.fr/test2';

  $(document).ready(function () {
    $('#my-test').load(function () {

        // when iframe has loaded, we replace the navbar's url by
        // the one from iframe's source.

        var History = window.History;
        if (History.enabled) {

            var url = $('#my-test').get(0).contentWindow.location.href;
            if (url.indexOf('blank') > 0) {
                return;
            }
            if (url.indexOf('test') > 0) {
                url = url.substring(url.indexOf('test2') + 5);
                if (url.length === 0) {
                    url = '/';
                }
            }

            var title = $("#my-test").contents().find("title").html();
            document.title = title;
            History.replaceState({}, title, window.test_url + decodeURIComponent(url + '')); // YES!

        }

    }).trigger('load'); // triggered once to replace main.html by a.html

});


</script>