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

发布于 2024-12-28 11:46:28 字数 113 浏览 2 评论 0原文

我正在开发一个网页,根据下一个或后一个操作我执行相应的动画,使用推送状态时会出现问题。当我收到事件时,我如何知道用户是否使用 Pushstate API 单击了后退或前进历史按钮?或者我是否必须自己实现某些功能?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

何以心动 2025-01-04 11:46:28

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

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

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.
陌上青苔 2025-01-04 11:46:28

以下内容应适用于单页应用程序、多页应用程序或两者的组合。

这个解决方案的关键在于 HTML 规范的要求
(或者曾经,如果我可以查找哪里)。
对于历史堆栈中的每个新条目,浏览器必须:(引用)

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

因此新条目的堆栈位置始终等于当前位置+1
(堆栈顶部)。随着新页面本身的出现,这将变为最后显示的位置+ 1

解决方案是:

  1. 在历史堆栈中为每个新条目标记其自己的位置
  2. 在会话存储中跟踪最后显示的位置
  3. 发现行进方向

通过比较两个示例代码

(已更正以修复 History.length bug 在 Mesqualito 的评论中得到解决。)

'use strict';

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

测试页面

这里是 测试显示代码运行的页面
其中包括一个变体,用本地存储替换会话,
但在其他方面是相同的。

限制

当我最初发布这个答案时,示例代码在我测试的所有浏览器中都有效,
包括火狐浏览器。现在它在 Firefox 下失败了(错误报告
除非您将代码从会话切换到本地存储(例如像这里) 。

该解决方案忽略页面的历史条目
与应用程序的原始域无关,就好像用户从未访问过它们一样。
它仅计算与显示的最后一个域页面相关的行进方向,
无论用户在其间访问过任何外部页面。
如果您希望用户将外部条目推送到历史堆栈上
(请参阅 Atosk 的评论),那么您可能需要一个解决方法。

The following should work with single-page apps, multi-page apps, or combinations of the two.

The key to this solution lies in what the HTML spec requires
(or used to, and probably still does if I could find where).
For each new entry to the history stack, the browser must: (quote)

  1. Remove all the entries in the browsing context’s session history after the current entry
  2. Append a new entry at the end

Therefore a new entry’s stack position is always going to equal current position + 1
(top of stack). With the appearance of the new page itself, this becomes position last shown + 1.

The solution then is:

  1. Stamp each new entry with its own position in the history stack
  2. Keep track in the session store of the position last shown
  3. Discover the direction of travel by comparing the two

Example code

(Corrected to fix the History.length bug addressed in Mesqualito’s comment.)

'use strict';

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

Test pages

Here are test pages that show the code running.
Included is a variant that replaces session with local storage,
but is otherwise the same.

Limitations

When I originally posted this answer, the example code worked in all the browsers I tested,
including Firefox. Nowadays it fails under Firefox (bug report)
unless you switch the code from session to local storage (e.g. like here).

This solution ignores the history entries of pages
foreign to the app’s domain of origin, as though the user had never visited them.
It calculates travel direction only in relation to the last domain page shown,
regardless of any foreign page that the user visited in between.
If you expect the user to push foreign entries onto the history stack
(see Atomosk’s comment), then you might need a workaround.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文