Javascript 如何检索popstate事件是否来自HTML5 pushstate的后退或前进操作?
我正在开发一个网页,根据下一步或下一步的动作,我会制作相应的动画,使用pushstate时会出现问题。当我收到事件时,我如何知道用户是否使用Pushstate API单击了“后退”或“前进”历史按钮?或者我是否必须自己实现某些功能 您必须自己实现它,这很容易Javascript 如何检索popstate事件是否来自HTML5 pushstate的后退或前进操作?,javascript,html,browser-history,pushstate,Javascript,Html,Browser History,Pushstate,我正在开发一个网页,根据下一步或下一步的动作,我会制作相应的动画,使用pushstate时会出现问题。当我收到事件时,我如何知道用户是否使用Pushstate API单击了“后退”或“前进”历史按钮?或者我是否必须自己实现某些功能 您必须自己实现它,这很容易 调用pushState时,为数据对象指定唯一的递增id(uid) 调用onpopstate处理程序时;对照包含最后一个状态uid的持久变量检查状态uid 使用当前状态uid更新持久变量 根据状态uid大于还是小于上一个状态uid,执行不同
- 调用
时,为数据对象指定唯一的递增id(uid)pushState
- 调用
处理程序时;对照包含最后一个状态uid的持久变量检查状态uidonpopstate
- 使用当前状态uid更新持久变量
- 根据状态uid大于还是小于上一个状态uid,执行不同的操作
历史.长度错误。)
工作原理
我们可以轻松地侦听历史堆栈中的新条目。
我们知道,对于每个新条目,都需要浏览器:
“删除当前条目之后浏览上下文会话历史记录中的所有条目”
“在末尾追加一个新条目”
因此,在进入时:
新输入位置=上次显示的位置+1
因此,解决办法是:
在每个历史记录条目的堆栈中标记其自己的位置
在上次显示的位置的会话存储中保持跟踪
通过比较两者来发现旅行的方向
示例代码
另请参见代码的一部分
限度
此解决方案忽略外部页面的历史记录条目,
与应用程序无关,好像用户从未访问过它们。
它仅根据最后显示的应用程序页面计算行驶方向,
不管其间访问了什么外部页面。
如果希望用户将外来项推送到堆栈上
(请参阅Atomosk的评论),然后您可能需要一个解决方法。popstate事件会显示“请更改为此状态”。它似乎假设您知道当前处于何种状态,因此需要执行哪些操作来更改状态。问题是历史是一个堆栈,因此如果我有一个列表,我向前、向前、向前、向后、向前、向前,列表是:[1,2,3,4,5],那么历史将是:[1,2,3,4,3,4]。在数字上是很容易的,但是在url上要知道哪个url是下一个,哪个是上一个并不是那么容易。下面bennedich的评论对我帮助很大。接受它可能会更好,这样它也能更有效地帮助他人。当页面/视图层次结构定义清楚时,这种方法效果很好,而且某个页面总是在另一个页面之后出现。当导航更加动态时,您不能依赖递增的UID。我已经通过使用sessionStorage来维护最后X页的堆栈来解决这个问题。然后,在popstate事件中,您可以从sessionStorage检查堆栈,以查看新页面URL是否与N-2页面的URL相同。使用sessionStorage而不是普通变量,因此这会在页面边界之间持久化。@frontendbeauty我认为您应该使用代码段发布您的建议作为答案。此外,不要检查值是否大于/小于,您可以编写一个状态更改管理器,检查id以查看当前状态是什么以及它将移动到什么状态,然后执行相应的动画如果这么简单,为什么不编写实现?对于任何可能的用例,我都看不出如何使其无bug。不管我在哪里保持当前状态,我都能找出如何滥用它。@如果你在页面上,你在中间页面B,你的堆栈看起来像这个代码[a,b,a]:<代码>你得到<代码> POPSTATE < /Cube >事件,你怎么知道它是返回还是前进?在你的站点上做一些导航,打开一个外部链接,按浏览器后退按钮两次,长按浏览器前进按钮并选择外部站点会话存储,然后按后退。也许我太过分了:)。另外,我认为您的函数可以替换为const direction=Math.sign(history.length-(sessionStorage.getItem('statelastshighed')| | 0));sessionStorage.setItem('stateLastShowed',history.length)代码>因为您总是将历史记录.length
置于历史记录状态。@Atomosk(1)您是对的,外部链接处理不正确。我加了一个警告。(2) 我认为你删减的代码会失败。仅确定堆栈中新条目的位置。您还需要代码来处理另一个案例,这是一个重新访问的条目。是的,您是对的。我永远不会习惯前端API是多么糟糕。用后退/前进按钮检查我能走多远应该是一行,但有人决定不这样做。浏览器后退/前进历史有一个固定的限制,在Chrome 50中。当您达到该限制时,history.length
将始终产生相同的数字(在我的情况下为50),因此此解决方案始终返回0作为方向,因为所有状态项都具有相同的位置。@Mesqalito您是对的,浏览器对history.length的限制使其不可靠。我将答案改为使用会话变量positionlastshighed
。
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) and forward (1)
}
addEventListener( 'pageshow', reorient );
addEventListener( 'popstate', reorient ); // Travel in same page