使用 HTML5 历史记录的后退按钮只能使用一次
Back button using HTML5 history works only once
我正在尝试为单页应用程序中的后退按钮构建一个简单的 javascript-only HTML5-only 实现。
作为第一步,我有一个可以工作的骨架原型,但只有一次 - 当我转到 1>2>3 然后从 3 返回时,它会回到 2,但仍然停留在 2无论我按下后退按钮多少次。行为总是相同的,并且跨浏览器,所以我确信这一定是我的逻辑,但即使经过多次尝试,我也无法弄清楚哪里出了问题。此外,前进按钮似乎也已停用。
简而言之,我有三个(隐藏的)div,每个都有一个(可见的)'description',单击它会打开实际的 div。页面加载时,只有描述和内容的 none 可见。当用户单击任何一个 div 的描述时,div 显示,其余的 are/remain 隐藏。
该站点位于 nginx 服务器后面,该服务器使用以下指令将所有内容传递到主页:
location /div1{
proxy_pass https://192.168.43.220:8765/;
}
由于比较简单,可以直接复制粘贴复制,所以冒昧的全部贴在这里。已经有计数器变量和许多 console.logs,所以这应该让试图修复它的人更容易。
如果能解释为什么这不起作用,我也将不胜感激。
<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>
好的,经过多轮调试和思考,我弄清楚了哪里出了问题。
show_div
函数都是将状态推送到历史中。因此,当 popstate
事件处理程序调用 js_route
函数时,它会调用正确的历史记录,但随后会将相同的状态推回到历史记录中。因此,当从 1 > 2 > 3,然后从 3 返回时,它会转到 2,但也会将 2 再次推入历史记录 - 因此再次返回将弹出历史记录中的最新状态,即现在的 2。从而创建无限循环任何进一步的 popstate 事件。
解决这个问题的方法是创建一组新的函数 - show_div_hist
与 show_div
函数做同样的事情,但不要将任何东西推入历史。类似地,一个新路由器 js_route_history
,它与 js_route
函数做同样的事情,但调用上述 show_div_hist
函数。
就是这样。效果很好。
<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>
我正在尝试为单页应用程序中的后退按钮构建一个简单的 javascript-only HTML5-only 实现。
作为第一步,我有一个可以工作的骨架原型,但只有一次 - 当我转到 1>2>3 然后从 3 返回时,它会回到 2,但仍然停留在 2无论我按下后退按钮多少次。行为总是相同的,并且跨浏览器,所以我确信这一定是我的逻辑,但即使经过多次尝试,我也无法弄清楚哪里出了问题。此外,前进按钮似乎也已停用。
简而言之,我有三个(隐藏的)div,每个都有一个(可见的)'description',单击它会打开实际的 div。页面加载时,只有描述和内容的 none 可见。当用户单击任何一个 div 的描述时,div 显示,其余的 are/remain 隐藏。
该站点位于 nginx 服务器后面,该服务器使用以下指令将所有内容传递到主页:
location /div1{
proxy_pass https://192.168.43.220:8765/;
}
由于比较简单,可以直接复制粘贴复制,所以冒昧的全部贴在这里。已经有计数器变量和许多 console.logs,所以这应该让试图修复它的人更容易。
如果能解释为什么这不起作用,我也将不胜感激。
<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>
好的,经过多轮调试和思考,我弄清楚了哪里出了问题。
show_div
函数都是将状态推送到历史中。因此,当 popstate
事件处理程序调用 js_route
函数时,它会调用正确的历史记录,但随后会将相同的状态推回到历史记录中。因此,当从 1 > 2 > 3,然后从 3 返回时,它会转到 2,但也会将 2 再次推入历史记录 - 因此再次返回将弹出历史记录中的最新状态,即现在的 2。从而创建无限循环任何进一步的 popstate 事件。
解决这个问题的方法是创建一组新的函数 - show_div_hist
与 show_div
函数做同样的事情,但不要将任何东西推入历史。类似地,一个新路由器 js_route_history
,它与 js_route
函数做同样的事情,但调用上述 show_div_hist
函数。
就是这样。效果很好。
<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>