前端浏览器前进后退传递信息

192 阅读6分钟

前端实现有两个页面page1和page2,page1跳转到page2,page2点击浏览器自带回退按钮回退到page1时,通过浏览器history api 给page1界面传递信息

我们使用浏览器 History API 来实现页面回退时传递信息的功能。与 localStorage 相比,History API 更适合处理页面间的状态信息,并且不会在浏览器存储中留下数据。

核心思路:

  1. Page1 跳转到 Page2:

    • 在跳转到 Page2 时,使用 history.pushState() 方法添加一个状态对象,其中包含一个标识符(例如,page1_visited=true)和一个用于传递信息的数据字段(初始值为空)。
  2. Page2 监听回退:

    • 在 Page2 中,监听浏览器的 popstate 事件。
    • popstate 事件触发时,如果历史记录中的 state 属性有 page1_visitedtrue 的记录,则表示从 Page1 而来。
    • 更新 state 中的数据字段,并使用 history.replaceState() 更新当前页面的历史记录状态,将信息传递给 Page1。
  3. Page1 监听 popstate:

    • 在 Page1 中,同样监听 popstate 事件。
    • popstate 事件触发时,检查 event.state 是否存在需要传递的信息,如果有则使用。

代码实现:

Page1 (index.html):

<!DOCTYPE html>
<html>
<head>
    <title>Page 1</title>
</head>
<body>
    <h1>Page 1</h1>
    <p id="message-display">Message from Page 2: </p>
    <button id="go-to-page2">Go to Page 2</button>

    <script>
        const messageDisplay = document.getElementById('message-display');
        const goToPage2Button = document.getElementById('go-to-page2');

        // 监听浏览器 popstate 事件
        window.addEventListener('popstate', (event) => {
            if (event.state && event.state.messageFromPage2) {
                messageDisplay.textContent = `Message from Page 2: ${event.state.messageFromPage2}`;
            }else {
                messageDisplay.textContent = 'Message from Page 2: No message received.';
            }

        });

        // 跳转到 Page 2
        goToPage2Button.addEventListener('click', () => {
            const state = { page1_visited: true, messageFromPage2: '' };
            history.pushState(state, '', 'page2.html');
             window.location.href = 'page2.html';
        });

    </script>
</body>
</html>

Page2 (page2.html):

<!DOCTYPE html>
<html>
<head>
    <title>Page 2</title>
</head>
<body>
    <h1>Page 2</h1>
    <p>This is Page 2.</p>

    <script>
        // 监听浏览器回退/前进事件
        window.addEventListener('popstate', (event) => {
            if (event.state && event.state.page1_visited) {
              // 传递信息
                const message = 'Hello from Page 2!';
                const newState = {...event.state, messageFromPage2: message}
                history.replaceState(newState, ''); // 更新历史记录状态
            }
        });
    </script>
</body>
</html>

代码讲解:

Page1 (index.html):

  1. messageDisplaygoToPage2Button: 获取页面上的元素。
  2. popstate 事件监听:
    • 监听浏览器的 popstate 事件,这个事件在点击回退或前进按钮时触发。
    • 检查 event.state 是否存在,并且 event.state 对象中是否存在 messageFromPage2 属性,如果有,则展示信息。
  3. goToPage2Button 点击事件:
    • 创建 state 对象,包含 page1_visited 标识和用于传递数据的 messageFromPage2
    • 使用 history.pushState(state, '', 'page2.html')state 对象添加到历史记录中,并通过 window.location.href跳转到 page2.html

Page2 (page2.html):

  1. popstate 事件监听:
    • 监听浏览器的 popstate 事件。
    • 检查 event.state 是否存在,且 event.state 对象中是否存在 page1_visited 属性。
    • 创建新的 newState 对象,把需要传递的信息赋值给 messageFromPage2 字段。
    • 使用 history.replaceState(newState, '') 更新当前页面的历史记录状态。

关键点总结:

  • history.pushState(state, title, url):
    • 用于向浏览器的历史记录添加一个状态。
    • state:状态对象,可以是任意 JavaScript 对象。
    • title:页面的标题(大多数浏览器会忽略)。
    • url:新页面的 URL。
  • history.replaceState(state, title):
    • 用于替换当前历史记录条目的状态。
    • state:新的状态对象。
    • title:页面的标题(大多数浏览器会忽略)。
  • popstate 事件: 当浏览器历史记录发生变化(通常是点击回退或前进按钮)时触发。
  • event.statepopstate 事件中,event.state 包含了当前历史记录条目的状态对象。

注意事项:

  • History API 依赖浏览器的历史记录,如果用户直接在地址栏中输入URL,或者使用非浏览器方式导航,可能不会触发 popstate 事件。
  • History API 只能传递简单的状态对象,不能传递复杂的对象或者函数,必要时需要进行序列化和反序列化。
  • 使用 History API 不会发起新的 HTTP 请求,只会更新浏览器的历史记录状态。

对比 localStorage:

  • History API:
    • 更适合管理页面间的状态信息。
    • 数据只在会话期间存在,不会长期存储。
    • 数据直接保存在历史记录中,方便获取。
  • localStorage:
    • 更适合存储持久化的数据。
    • 数据在浏览器关闭后仍然存在。
    • 需要手动清理。

总的来说,如果只是需要在页面跳转回退时传递信息,使用 History API 更加优雅和自然。

点滴积累

当用户点击浏览器的前进或后退按钮时,浏览器会先触发 popstate 事件,然后再进行页面的前进或后退操作。以下是详细的解释:

事件触发顺序:

  1. 用户点击前进/后退按钮:

    • 用户在浏览器中点击前进或后退按钮。
  2. popstate 事件触发:

    • 浏览器会立即触发当前页面的 popstate 事件。这个事件的触发不会导致页面重新加载,而是会通知当前页面,浏览器的历史记录发生了变化。
    • popstate 事件的 event 对象包含 state 属性,其中存储了该历史记录条目的状态对象(如果使用 history.pushStatehistory.replaceState 添加了状态的话)。
  3. 页面状态更新(可选):

    • popstate 事件的监听器中,你可以根据 event.state 的值来更新当前页面的状态,比如改变页面上的某些数据或 UI 显示。
    • 如果你使用了 history.pushStatehistory.replaceState 修改了历史记录,那么你可以在 popstate 事件中利用 event.state 来恢复对应的状态。
    • 需要注意的是,此时页面并没有真正刷新或者重新加载。
  4. 页面前进/后退:

    • popstate 事件处理完毕后,浏览器才会真正地前进或后退到相应的页面。
    • 如果前进/后退的页面没有被缓存,浏览器会进行页面的重新渲染或加载。
    • 如果前进/后退的页面被缓存,浏览器会从缓存中读取,会触发该页面的 pageshow 事件,并且此时的 pageshow 事件中的 event.persisted 属性会被设置为 true。
    • 如果用户点击回退或者前进时,页面没有产生缓存,则会触发新页面的 load 事件。

popstate 事件的特点:

  • 不引起页面重载: popstate 事件的触发不会导致页面的重新加载或刷新。它只是通知当前页面,历史记录发生了变化。
  • 可以获取历史状态: event.state 属性允许你获取与历史记录条目相关联的状态对象,这对于实现单页应用 (SPA) 的路由非常有用。
  • pushStatereplaceState 之后才会触发: 只有使用了 history.pushStatehistory.replaceState 修改了浏览器的历史记录,且用户点击了前进/后退按钮时,才会触发 popstate 事件。

pageshow 事件的特点:

  • 可以监听缓存页面: pageshow 事件允许你监听页面是从浏览器缓存加载的情况。
  • event.persisted 属性: 该属性标识了当前页面是否是从缓存加载。

理解这个执行顺序对于正确处理单页应用中的路由和页面状态非常重要。 使用 popstate 事件,可以无缝地更新页面内容,实现更加流畅的用户体验。