使用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"]
.
那么,作为一种替代方案,有没有办法在不推动新状态的情况下消除"前进"历史?
1> Mike B...:
你可能已经开始了,但是......据我所知,没有办法删除历史记录条目(或状态).
我一直在研究的一个选择是用Javascript自己处理历史,并将window.history
对象用作各种类型的载体.
基本上,当页面首次加载时,您将创建自定义历史记录对象(我们将在此处使用数组,但使用对您的情况有意义的任何内容),然后执行初始化pushState
.我会将您的自定义历史记录对象作为状态对象传递,因为如果您还需要处理远离您的应用程序并稍后返回的用户,它可能会派上用场.
var myHistory = [];
function pageLoad() {
window.history.pushState(myHistory, "", "");
//Load page data.
}
现在,当您导航时,您将添加到您自己的历史对象(或者不会 - 历史记录现在在您手中!)并用于replaceState
使浏览器远离循环.
function nav_to_details() {
myHistory.push("page_im_on_now");
window.history.replaceState(myHistory, "", "");
//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, "", "");
//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 },
"",
""
);
// 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 },
"",
""
);
// We also need to start our history tracking.
myHistory.push("");
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 }, "", "");
}
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.
//
//
//
// 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 },
"",
""
);
} 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();
//
// And push them to our "app" page again
window.history.pushState(
{ isBackPage: false },
"",
""
);
} 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)
}
}