JS - window.history - 删除状态

问题描述 投票:38回答:2

使用html5 window.history API,我可以在我的网络应用程序上很好地控制导航。

该应用程序目前有两个州:selectDate(1)和enterDetails(2)。

当应用程序加载时,我replaceState并设置一个popState监听器:

history.replaceState({stage:"selectDate",...},...);
window.onpopstate = function(event) {
    that.toStage(event.state.stage);
};

选择日期并且应用程序移至第2阶段时,我将状态2推入堆栈:

history.pushState({stage:"enterDetails",...},...);

只要细节发生变化,就会替换此状态,以便将它们保存在历史记录中。

离开第二阶段有三种方法:

  • 保存(ajax提交)
  • 取消
  • 返回键

后退按钮由popstate监听器处理。取消按钮按下阶段1,以便用户可以返回他们进入后退按钮的详细信息。这两个都很好。

保存按钮应恢复到第1阶段,不允许用户导航回详细信息页面(因为他们已经提交)。基本上,它应该使历史堆栈长度= 1。

但似乎没有history.delete(),或history.merge()。我能做的最好的是一个history.replaceState(stage1),它将历史堆栈保留为:["selectDate","selectDate"]

如何摆脱一层?

编辑:

想到别的东西,但它也不起作用。

history.back(); //moves history to the correct position
location.href = "#foo"; // successfully removes ability to go 'forward', 
                       // but also adds another layer to the history stack

这使历史堆栈成为["selectDate","selectDate#foo"]

那么,作为一种替代方案,有没有办法在不推动新状态的情况下消除“前进”历史?

javascript html html5 browser-history
2个回答
54
投票

你可能已经开始了,但是......据我所知,没有办法删除历史记录条目(或状态)。

我一直在研究的一个选择是用JavaScript自己处理历史,并使用window.history对象作为各种载体。

基本上,当页面首次加载时,您创建自定义历史记录对象(我们将在这里使用数组,但使用对您的情况有意义的任何内容),然后执行您的初始pushState。我会将您的自定义历史记录对象作为状态对象传递,因为如果您还需要处理远离您的应用程序并稍后返回的用户,它可能会派上用场。

var myHistory = [];

function pageLoad() {
    window.history.pushState(myHistory, "<name>", "<url>");

    //Load page data.
}

现在当你导航时,你会添加到你自己的历史对象中(或者不是 - 历史记录现在在你手中!)并使用replaceState来保持浏览器不在循环中。

function nav_to_details() {
    myHistory.push("page_im_on_now");
    window.history.replaceState(myHistory, "<name>", "<url>");

    //Load page data.
}

当用户向后导航时,它们将处于“基本”状态(您的状态对象将为空),您可以根据自定义历史记录对象处理导航。之后,您执行另一个pushState。

function on_popState() {
    // Note that some browsers fire popState on initial load,
    // so you should check your state object and handle things accordingly.
    // (I did not do that in these examples!)

    if (myHistory.length > 0) {
        var pg = myHistory.pop();
        window.history.pushState(myHistory, "<name>", "<url>");

        //Load page data for "pg".
    } else {
        //No "history" - let them exit or keep them in the app.
    }
}

用户永远无法使用浏览器按钮向前导航,因为他们始终位于最新页面上。

从浏览器的角度来看,每次他们“退回”时,他们都会立即再次向前推进。

从用户的角度来看,他们能够向后浏览页面但不能前进(基本上模拟智能手机“页面堆栈”模型)。

从开发人员的角度来看,您现在可以高度控制用户浏览应用程序的方式,同时仍然允许他们使用浏览器上熟悉的导航按钮。您可以根据需要在历史链中的任何位置添加/删除项目。如果在历史数组中使用对象,则还可以跟踪有关页面的额外信息(如字段内容和诸如此类的内容)。

如果您需要处理用户启动的导航(例如用户在基于散列的导航方案中更改URL),那么您可能会使用稍微不同的方法,如...

var myHistory = [];

function pageLoad() {
    // When the user first hits your page...
    // Check the state to see what's going on.

    if (window.history.state === null) {
        // If the state is null, this is a NEW navigation,
        //    the user has navigated to your page directly (not using back/forward).

        // First we establish a "back" page to catch backward navigation.
        window.history.replaceState(
            { isBackPage: true },
            "<back>",
            "<back>"
        );

        // Then push an "app" page on top of that - this is where the user will sit.
        // (As browsers vary, it might be safer to put this in a short setTimeout).
        window.history.pushState(
            { isBackPage: false },
            "<name>",
            "<url>"
        );

        // We also need to start our history tracking.
        myHistory.push("<whatever>");

        return;
    }

    // If the state is NOT null, then the user is returning to our app via history navigation.

    // (Load up the page based on the last entry of myHistory here)

    if (window.history.state.isBackPage) {
        // If the user came into our app via the back page,
        //     you can either push them forward one more step or just use pushState as above.

        window.history.go(1);
        // or window.history.pushState({ isBackPage: false }, "<name>", "<url>");
    }

    setTimeout(function() {
        // Add our popstate event listener - doing it here should remove
        //     the issue of dealing with the browser firing it on initial page load.
        window.addEventListener("popstate", on_popstate);
    }, 100);
}

function on_popstate(e) {
    if (e.state === null) {
        // If there's no state at all, then the user must have navigated to a new hash.

        // <Look at what they've done, maybe by reading the hash from the URL>
        // <Change/load the new page and push it onto the myHistory stack>
        // <Alternatively, ignore their navigation attempt by NOT loading anything new or adding to myHistory>

        // Undo what they've done (as far as navigation) by kicking them backwards to the "app" page
        window.history.go(-1);

        // Optionally, you can throw another replaceState in here, e.g. if you want to change the visible URL.
        // This would also prevent them from using the "forward" button to return to the new hash.
        window.history.replaceState(
            { isBackPage: false },
            "<new name>",
            "<new url>"
        );
    } else {
        if (e.state.isBackPage) {
            // If there is state and it's the 'back' page...

            if (myHistory.length > 0) {
                // Pull/load the page from our custom history...
                var pg = myHistory.pop();
                // <load/render/whatever>

                // And push them to our "app" page again
                window.history.pushState(
                    { isBackPage: false },
                    "<name>",
                    "<url>"
                );
            } else {
                // No more history - let them exit or keep them in the app.
            }
        }

        // Implied 'else' here - if there is state and it's NOT the 'back' page
        //     then we can ignore it since we're already on the page we want.
        //     (This is the case when we push the user back with window.history.go(-1) above)
    }
}

1
投票

无法删除或阅读过去的历史记录。

您可以尝试通过在自己的内存中模拟历史记录并在每次发出history.pushState事件时调用popstate(由the currently accepted Mike's answer提出),但它有很多缺点会导致UX比不支持浏览器历史记录更糟糕在你的动态网络应用程序中,因为:

  • popstate事件可以在用户返回2-3个状态时发生
  • popstate事件可以在用户前进时发生

因此,即使您尝试通过构建虚拟历史来绕过它,它很可能也会导致您有空白历史状态(返回/转发什么都不做)的情况,或者返回/转发的地方跳过某些状态你的历史总是说明。

© www.soinside.com 2019 - 2024. All rights reserved.