如果 popstate 事件来自 HTML5 pushstate 的后退或前进操作,我如何检索?

我正在开发一个网页,在那里取决于下一个或后退的行动,我做相应的动画,问题出现时,使用推状态。当我接收到事件时,如何知道用户是使用 Pushstate API 单击回退还是转发历史按钮?还是要我亲自动手?

43170 次浏览

你必须自己实现它,这很容易。

  • 当调用 pushState时,给数据对象一个惟一的递增 id (uid)。
  • 调用 onpopstate处理程序时,根据包含最后一个 state uid 的持久变量检查 state uid。
  • 使用当前状态 uid 更新持久变量。
  • 根据状态 uid 大于或小于上一个状态 uid,执行不同的操作。

这个答案应该可以在一个单页面的推送状态应用程序中使用, 或者一个多页面的应用程序,或者两者的结合。 (修正了 Mesqualito 评论中提到的 History.length漏洞。)

它是如何工作的

我们可以很容易地侦听历史堆栈的新条目。 我们知道,对于每个新条目,规格要求浏览器:

  1. “删除当前条目后浏览上下文会话历史记录中的所有条目”
  2. “在末尾附加一个新条目”

因此,在进入时刻:

新的入口位置 = 上次显示的位置 + 1

那么解决办法就是:

  1. 在每个历史记录条目上标记其在堆栈中的位置
  2. 在上次显示的位置的会话存储中保持跟踪
  3. 通过比较两者来发现旅行的方向

示例代码

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

请参阅代码的 现场直播

限制

此解决方案忽略外部页的历史记录项, 外来的应用程序,好像用户从来没有访问过他们。 它只根据最后显示的应用程序页面计算旅行方向, 不管中间访问过什么外部页面。 如果期望用户将外部条目推送到堆栈上 (参见 Atomosk 的评论) ,那么您可能需要一个变通方法。