简体   繁体   English

使用HTML5历史记录的“后退”按钮只能使用一次

[英]Back button using HTML5 history works only once

I am trying to build a simple javascript-only HTML5-only implementation for the back button in a single page app. 我正在尝试为单页应用程序中的“后退”按钮构建一个仅使用JavaScript的HTML5的简单实现。

As a first step, I have a skeletal prototype which works, but only once - when I go 1>2>3 and then press back from 3, it comes back to 2 alright, but remains stuck there at 2 no matter how many times more I press the back button. 第一步,我有一个可以工作的骨骼原型,但是只有一次-当我进入1> 2> 3,然后从3按下时,它回到2好了,但是无论多少次,它都停留在2我按返回按钮。 The behavior is always the same, and across browsers, so I am sure it must be my logic, but even after many tries I am unable to figure what's broken. 在所有浏览器中,行为始终是相同的,因此,我确定这必须是我的逻辑,但是即使经过多次尝试,我也无法弄清到底是什么。 Further, the forward button also seems to be deactivated. 此外,前进按钮似乎也被禁用。

To explain it briefly, I have three (hidden) divs and for each there is a (visible) 'description', clicking on which opens the actual div. 为了简要说明,我有三个(隐藏的)div,每个都有一个(可见的)“说明”,单击可打开实际的div。 When the page loads, only the descriptions are visible and none of the content. 页面加载时,只有描述是可见的,没有内容。 When the user clicks on the description of any one div, that div shows, and the rest are/remain hidden. 当用户单击任何一个div的描述时,该div就会显示,其余的/将保持隐藏状态。

The site is behind an nginx server which proxy passes everything to the homepage with directives like: 该站点位于nginx服务器的后面,该服务器通过以下指令将所有内容传递到首页:

location /div1{
        proxy_pass https://192.168.43.220:8765/;
    }

Since it is relatively simple, and can be directly copy pasted to replicate, I am taking the liberty of pasting it all here. 由于它相对简单,并且可以直接复制粘贴以复制,因此我将所有内容都粘贴在这里。 There are already counter variables and many console.logs, so that should make it easier for someone trying to fix it. 已经有计数器变量和许多console.logs,因此对于尝试修复它的人来说应该更容易。

I would also appreciate any explanation of why this doesn't work. 我也很感谢任何关于为什么这行不通的解释。

<html>
<head>
</head>
<body>
    <b href="#div1" onclick=show_div1()>DIV1</b>
    <b href="#div2" onclick=show_div2()>DIV2</b>
    <b href="#div3" onclick=show_div3()>DIV3</b>

    <div id="div1">
        <p>This is div number 1</p>
    </div>
    <div id="div2">
        <p>This is div number 2</p>
    </div>
    <div id="div3">
        <p>This is div number 3</p>
    </div>
</body>

<script>
    document.addEventListener("DOMContentLoaded", function(event){
        on_page_load();
    });
    function on_page_load(){
        document.getElementById("div1").style.display="none";
        document.getElementById("div2").style.display="none";
        document.getElementById("div3").style.display="none";
        var p = window.location.pathname.split("/")[1];
        console.log("on page load, pathname: " + p);
        history.pushState({url: p}, null, p);
        console.log("js routing to: " + p);
        js_route(p);
        n1 = 0; n2 = 0; n3 = 0;
    }
    function show_div1(){
        document.getElementById("div1").style.display="block";
        document.getElementById("div2").style.display="none";
        document.getElementById("div3").style.display="none";
        n1 = n1 + 1;
        console.log("showing div1 for " + n1 + "th time");
        history.pushState({url: 'div1', n: n1}, null, "div1");
    }
    function show_div2(){
        document.getElementById("div2").style.display="block";
        document.getElementById("div1").style.display="none";
        document.getElementById("div3").style.display="none";
        n2 = n2 + 1;
        console.log("showing div2 for " + n2 + "th time");
        history.pushState({url: 'div2', n: n2}, null, "div2");
    }
    function show_div3(){
        document.getElementById("div3").style.display="block";
        document.getElementById("div2").style.display="none";
        document.getElementById("div1").style.display="none";
        n3 = n3 + 1;
        console.log("showing div3 for " + n3 + "th time");
        history.pushState({url: 'div3', n: n3}, null, "div3");
    }

    window.onpopstate = function(event) {
        var popped_url = event.state.url;
        var popped_n = event.state.n;
        console.log("popstate url: " + popped_url);
        console.log("onpopstate, routing to: " + window.location.pathname + " and n is " + popped_n);
        js_route(popped_url);
        //js_route(window.location.pathname.split("/")[1]);
    }

    function js_route(path){
        switch(path){
            case "div1":
                show_div1();
                break;
            case "div2":
                show_div2();
                break;
            case "div3":
                show_div3();
        }
    }
</script>

Ok, after many more rounds of debugging and contemplation, I figured out what was broken. 好的,经过多轮调试和沉思,我弄清楚了什么是坏的。

The show_div functions all push state into the history. show_div函数都将状态推送到历史记录中。 So, when the popstate event handler calls the js_route function, it calls up the correct history, but then pushes that same state back into history. 因此,当popstate事件处理程序调用js_route函数时,它将调用正确的历史记录,然后将相同的状态推回到历史记录中。 So, when going from 1>2>3, and then back from 3, it goes to 2, but also pushes 2 again into history - so going back again will pop the latest state in history which is now 2. Thus creating an infinite loop on any further popstate events. 因此,当从1> 2> 3转到3时,返回到2,又将2推入历史记录-因此再次返回将弹出历史记录中最新的状态,即现在为2。在任何其他popstate事件上循环播放。

The way around this is to create a new set of functions - show_div_hist which do the same thing as the show_div functions, but do not push anything into history. 解决此问题的方法是创建一组新的函数show_div_hist ,它们与show_div函数具有相同的功能,但不会将任何内容推入历史记录。 Similarly, a new router js_route_history , which does the same thing as the js_route function but calls up the aforementioned show_div_hist functions instead. 类似地,一个新的路由器js_route_history ,其功能与js_route函数相同,但会调用上述的show_div_hist函数。

And that's it. 就是这样。 Works nicely. 效果很好。

<html>
    <head>
    </head>
    <body>
        <b href="#div1" onclick=show_div1()>DIV1</b>
        <b href="#div2" onclick=show_div2()>DIV2</b>
        <b href="#div3" onclick=show_div3()>DIV3</b>

        <div id="div1">
            <p>This is div number 1</p>
        </div>
        <div id="div2">
            <p>This is div number 2</p>
        </div>
        <div id="div3">
            <p>This is div number 3</p>
        </div>
    </body>

    <script>
        document.addEventListener("DOMContentLoaded", function(event){
            on_page_load();
        });
        function on_page_load(){
            document.getElementById("div1").style.display="none";
            document.getElementById("div2").style.display="none";
            document.getElementById("div3").style.display="none";
            document.getElementById("div4").style.display="none";
            var p = window.location.pathname.split("/")[1];
            console.log("on page load, pathname: " + p);
            history.pushState({url: p}, null, p);
            console.log("js routing to: " + p);
            js_route(p);
            n1 = 0; n2 = 0; n3 = 0;
        }
        function show_div1(){
            document.getElementById("div1").style.display="block";
            document.getElementById("div2").style.display="none";
            document.getElementById("div3").style.display="none";
            document.getElementById("div4").style.display="none";
            n1 = n1 + 1;
            //console.log("showing div1 for " + n1 + "th time");
            history.pushState({url: 'div1', n: n1}, null, "div1");
        }
        function show_div1_hist(){
            document.getElementById("div1").style.display="block";
            document.getElementById("div3").style.display="none";
            document.getElementById("div2").style.display="none";
            document.getElementById("div4").style.display="none";
//          n1 = n1 + 1;
//          console.log("showing div1 for " + n1 + "th time");
//          history.pushState({url: 'div1', n: n1}, null, "div1");
        }

        function show_div2(){
            document.getElementById("div2").style.display="block";
            document.getElementById("div1").style.display="none";
            document.getElementById("div3").style.display="none";
            document.getElementById("div4").style.display="none";
            n2 = n2 + 1;
            //console.log("showing div2 for " + n2 + "th time");
            history.pushState({url: 'div2', n: n2}, null, "div2");
        }
        function show_div2_hist(){
            document.getElementById("div2").style.display="block";
            document.getElementById("div1").style.display="none";
            document.getElementById("div3").style.display="none";
            document.getElementById("div4").style.display="none";
//          n2 = n2 + 1;
//          console.log("showing div2 for " + n2 + "th time");
//          history.pushState({url: 'div2', n: n2}, null, "div2");
        }


        function show_div3(){
            document.getElementById("div3").style.display="block";
            document.getElementById("div2").style.display="none";
            document.getElementById("div4").style.display="none";
            document.getElementById("div1").style.display="none";
            n3 = n3 + 1;
            //console.log("showing div3 for " + n3 + "th time");
            history.pushState({url: 'div3', n: n3}, null, "div3");
        }
        function show_div3_hist(){
            document.getElementById("div3").style.display="block";
            document.getElementById("div2").style.display="none";
            document.getElementById("div1").style.display="none";
            document.getElementById("div4").style.display="none";
//          n3 = n3 + 1;
//          console.log("showing div3 for " + n3 + "th time");
//          history.pushState({url: 'div3', n: n3}, null, "div3");
        }
        window.onpopstate = function(event) {
            event.preventDefault();
            var popped_url = event.state.url;
            var popped_n = event.state.n;
            console.log("popstate url: " + popped_url);
            console.log("onpopstate, routing to: " + window.location.pathname + " and n is " + popped_n);
            js_route_hist(popped_url);
            //js_route(window.location.pathname.split("/")[1]);
        }

        function js_route(path){
            switch(path){
                case "div1":
                    show_div1();
                    break;
                case "div2":
                    show_div2();
                    break;
                case "div3":
                    show_div3();
            }
        }
        function js_route_hist(path){
            switch(path){
                case "div1":
                    show_div1_hist();
                    break;
                case "div2":
                    show_div2_hist();
                    break;
                case "div3":
                    show_div3_hist();
            }
        }

    </script>
</html>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM