需要点击两次才能回到历史(使用pushState)
Posted
技术标签:
【中文标题】需要点击两次才能回到历史(使用pushState)【英文标题】:Need to click twice to go back in history (using pushState) 【发布时间】:2014-07-07 12:18:36 【问题描述】:我有一个包含一些选择字段的页面。 一旦用户更改了选择字段的值,就会使用所有选择字段的值作为状态对象创建一个新的历史对象:
$(".chosen-select-field").chosen().change(function()
$(".chosen-select-field").each( function ( index )
parameterNames[index].value = $( this ).val();
);
history.pushState(parameterNames, '', newUrl);
);
parameterNames 是一个包含键和值的对象数组,例如
parameterNames.push(key:"name", value:"foobar");
以下代码会在用户单击浏览器中的后退或前进按钮时恢复状态。它有效,但行为异常。
例如,我更改了三个选择字段(创建三个历史条目)。然后我回去。执行 restoreState 时,一个选择字段会相应更改。但是浏览器本身在历史记录中的位置保持不变(不能前进,仍然是相同数量的回溯历史条目)。
然后我再次单击后退按钮。这次状态对象与我单击的列表时间相同。不过,浏览器会在历史记录中向后移动一个条目。
第三次单击后退按钮时,下一个选择字段会更改,但浏览器会再次保持该状态,除非我第四次单击。
谁能解释我做错了什么?
var restoreState = function(event)
event = event.originalEvent;
parameterNames = event.state;
$(".chosen-select-field").each( function ( index )
if ($( this ).val() != parameterNames[index].value)
$( this ).val(parameterNames[index].value).change();
$( this ).trigger('chosen:updated');
);
;
// Bind history events
$(window).bind("popstate",restoreState);
【问题讨论】:
在 popstate(例如返回)上,您正在调用“restoreState”,它循环字段,并可能调用 .change(),它再次执行 history.pushState。如果 popstate 事件被触发,我建议执行 replaceState。 ***.com/questions/20156939/… 【参考方案1】:当 popstate 事件被触发并循环选择字段时,如果满足$( this ).val() != parameterNames[index].value
条件,则当前选择值将被更改,但也会触发 change 事件,进而再次调用将新状态推入历史的功能。这样,如果你回到历史,你会得到相同的状态对象。
因此,解决方案是检查是否触发了 popstate 事件,如果是,则不要调用 history.pushState
,而是调用 history.replaceState
。
function handleHistoryStates(popstateEventWasFired = false)
$(".chosen-select-field").each( function ( index )
parameterNames[index].value = $( this ).val();
);
if (popstateEventWasFired)
history.replaceState(parameterNames, '', newUrl);
else
history.pushState(parameterNames, '', newUrl);
$(".chosen-select-field").chosen().change(handleHistoryStates);
var restoreState = function(event)
event = event.originalEvent;
parameterNames = event.state;
$(".chosen-select-field").each( function ( index )
if ($( this ).val() != parameterNames[index].value)
$( this ).val(parameterNames[index].value);
handleHistoryStates(true);
$( this ).trigger('chosen:updated');
);
;
// Bind history events
$(window).bind("popstate",restoreState);
【讨论】:
【参考方案2】:我猜你是Pushing
当你到达状态时的当前状态,而不是当你到达当前状态时你推送上一个状态..
这就是为什么当你第一次按下后退按钮时你会弹出当前状态,而你需要弹出前一个状态并去那里......
let boxes = Array.from(document.getElementsByClassName('box'));
function selectBox(id)
boxes.forEach(b =>
b.classList.toggle('selected', b.id === id);
);
boxes.forEach(b =>
let id = b.id;
b.addEventListener('click', e =>
history.pushState(
id
, `Selected: $id`, `./selected=$id`)
selectBox(id);
);
);
window.addEventListener('popstate', e =>
selectBox(e.state.id);
);
history.replaceState(
id: null
, 'Default state', './');
.boxes
display: flex;
.desc
width: 100%;
display: flex;
align-items: center;
padding: 3rem 0;
justify-content: center;
font-weight: bold;
.box
--box-color: black;
width: 50px;
height: 50px;
margin: 20px;
box-sizing: border-box;
display: block;
border-radius: 2px;
cursor: pointer;
color: white;
background-color: var(--box-color);
border: 5px solid var(--box-color);
font-size: 14px;
font-family: sans-serif;
font-weight: bold;
text-align: center;
line-height: 20px;
transition: all 0.2s ease-out;
.box:hover
background-color: transparent;
color: black;
.box.selected
transform: scale(1.2);
#box-1
--box-color: red;
#box-2
--box-color: green;
#box-3
--box-color: blue;
#box-4
--box-color: black;
<div class="boxes">
<div class="box" id="box-1">one</div>
<div class="box" id="box-2">two</div>
<div class="box" id="box-3">three</div>
<div class="box" id="box-4">four</div>
</div>
<div class="desc">
Click to select Each box and u can navigate back using browser back button
</div>
检查此代码笔:https://codepen.io/AmalNandan/pen/VwmrQJM?editors=1100
【讨论】:
以上是关于需要点击两次才能回到历史(使用pushState)的主要内容,如果未能解决你的问题,请参考以下文章
使用 window.history.pushState 函数时无法在“历史”错误上执行“pushState”
UITableView:reloadRows(at:) 需要两次点击才能更新表并每次滚动