Javascript 如果 popstate 事件来自 HTML5 pushstate 的后退或前进操作,我如何检索?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8980255/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I retrieve if the popstate event comes from back or forward actions with the HTML5 pushstate?
提问by Davsket
I'm developing a webpage where depending on the next or back actions I do the correspondent animation, the problem comes when using the pushstate. When I receive the event how do I know if the user clicked back or forward history buttons using the Pushstate API?, or do I have to implement something myself?
我正在开发一个网页,根据我执行相应动画的下一个或后退动作,问题出现在使用 pushstate 时。当我收到事件时,我如何知道用户是否使用 Pushstate API 单击了后退或前进历史按钮?还是我必须自己实现一些东西?
回答by bennedich
You must implement it yourself which is quite easy.
你必须自己实现它,这很容易。
- When invoking
pushState
give the data object a unique incrementing id (uid). - When
onpopstate
handler is invoked; check the state uid against a persistent variable containing the last state uid. - Update the persistent variable with the current state uid.
- Do different actions depending on if state uid was greater or less than last state uid.
- 调用时
pushState
给数据对象一个唯一的递增 id (uid)。 - 当
onpopstate
处理程序被调用时;根据包含最后一个状态 uid 的持久变量检查状态 uid。 - 使用当前状态 uid 更新持久变量。
- 根据状态 uid 是大于还是小于上一个状态 uid 执行不同的操作。
回答by Michael Allan
This answer should work with a single page push-state app,
or a multi-page app, or a combination of the two.
(Corrected to fix the History.length
bug addressed in Mesqualito's comment.)
此答案应适用于单页推送状态应用程序、多页应用程序或两者的组合。
(更正以修复History.length
Mesqualito 评论中解决的错误。)
How it works
这个怎么运作
We can easily listen for new entries to the history stack. We know that for each new entry, the specificationrequires the browser to:
我们可以轻松地侦听历史堆栈的新条目。我们知道,对于每个新条目,规范要求浏览器:
- “Remove all the entries in the browsing context's session history after the current entry”
- “Append a new entry at the end”
- “在当前条目之后删除浏览上下文会话历史记录中的所有条目”
- “在最后添加一个新条目”
At the moment of entry, therefore:
因此,在进入时:
new entry position = position last shown + 1
新入场位置 = 最后显示的位置 + 1
The solution then is:
那么解决办法是:
- Stamp each history entry with its own position in the stack
- Keep track in the session store of the position last shown
- Discover the direction of travel by comparing the two
- 用它在堆栈中的位置标记每个历史条目
- 在会话存储中跟踪最后显示的位置
- 通过比较两者来发现行进方向
Example code
示例代码
function reorient() // After travelling in the history stack
{
const positionLastShown = Number( // If none, then zero
sessionStorage.getItem( 'positionLastShown' ));
let position = history.state; // Absolute position in stack
if( position === null ) // Meaning a new entry on the stack
{
position = positionLastShown + 1; // Top of stack
// (1) Stamp the entry with its own position in the stack
history.replaceState( position, /*no title*/'' );
}
// (2) Keep track of the last position shown
sessionStorage.setItem( 'positionLastShown', String(position) );
// (3) Discover the direction of travel by comparing the two
const direction = Math.sign( position - positionLastShown );
console.log( 'Travel direction is ' + direction );
// One of backward (-1), reload (0) or forward (1)
}
addEventListener( 'pageshow', reorient );
addEventListener( 'popstate', reorient ); // Travel in same page
See also a live copyof the code.
另请参阅代码的实时副本。
Limitation
局限性
This solution ignores the history entries of external pages, foreign to the application, as though the user had never visited them. It calculates travel direction only in relation to the last shown application page, regardless of any external page visited in between. If you expect the user to push foreign entries onto the stack (see Atomosk's comment), then you might need a workaround.
此解决方案忽略外部页面的历史记录条目,对于应用程序来说是陌生的,就好像用户从未访问过它们一样。它仅计算与上次显示的应用程序页面相关的行进方向,而不管其间访问过的任何外部页面。如果您希望用户将外部条目推送到堆栈上(请参阅 Atomosk 的评论),那么您可能需要一种解决方法。