如何跨页面传递浏览器的会话状态?

How to transfer browser’s session state across pages?

我想实现一个绑定到浏览器会话历史记录客户端购物车。这意味着添加到购物车或从购物车中删除的每个项目都应该创建一个新的会话状态,并且在会话历史记录中返回或前进应该相应地影响购物车。

据我所知,只有 History API allows storing data in the session state (HTTP cookies and the Web storage API 将数据存储在浏览器的其他位置)。所以这是一个购物页面的代码片段,它允许用户将商品添加到他的购物车,打断他的 activity 以转到主页并稍后恢复,以及在会话中返回或前进购物车更改的历史记录:

<!DOCTYPE html>
<html lang="en">
<title>Test</title>
<script>
addEventListener("load", function (event) {
  function setup(data) {
    let element = document.getElementById("data");
    element.textContent = data;
  }
  for (let link of document.links) {
    link.addEventListener("click", function (event) {
      event.preventDefault();
      let data = history.state || [];
      if (link.href.includes("item=")) {
        data.push(link.textContent);
      }
      history.pushState(data, "", link.href);
      setup(history.state);
    });
  }
  addEventListener("popstate", function (event) {
    setup(event.state);
  });
  setup(history.state);
});
</script>
<p>Control:
  <a href="?home">home</a> <a href="?shop">shop</a>
  <a href="?item=1">item1</a> <a href="?item=2">item2</a>
</p>
<p>Data: <span id="data"></span></p>
</html>

为了在会话状态之间传输购物车数据,我通过附加一个调用方法 history.pushState(data, "", uri) 的点击事件侦听器覆盖了浏览器对页面所有超链接上点击事件的默认重定向行为。这似乎可行,但这些会话状态转换并没有真正改变页面,它们只改变了 URI。因此,对于每个会话状态转换,我还必须在原始页面(此处为购物页面)中加载目标页面(此处为主页)的 HTML,这导致了我的问题:

如何跨页面传递浏览器会话状态?

如果不同的选项卡可以有不同的购物车,或者关闭选项卡会破坏购物车并不重要,请查看 session storage api。它在会话中存储东西。

我终于想出了一个涉及 History API and the Web storage API 的解决方案。对于添加到购物车的每个项目,我使用 Web 存储 API 将项目存储在浏览器会话存储中的购物车数组中,以便项目跨页面持久存在。我还使用 History API 将商品和购物车数组的长度存储在浏览器会话历史的新会话状态中,这样当用户返回或转发到此会话状态时,我可以更新购物相应地浏览器会话存储中的购物车数组。

<!DOCTYPE html>
<html lang="en">
<title>Test</title>
<script>
addEventListener("load", function (event) {
  function setup(data) {
    let element = document.getElementById("data");
    element.textContent = data;
  }
  for (let link of document.links) {
    if (link.href.includes("item=")) {
      link.addEventListener("click", function (event) {
        event.preventDefault();
        if (!("cart" in sessionStorage)) {
          sessionStorage.cart = JSON.stringify([]);
        }
        let cart = JSON.parse(sessionStorage.cart);
        cart.push(link.textContent);
        sessionStorage.cart = JSON.stringify(cart);
        let state = {
          cartLength: cart.length,
          cartItem: link.textContent
        };
        history.pushState(state, "");
        setup(cart);
      });
    }
  }
  addEventListener("popstate", function (event) {
    if (!("cart" in sessionStorage)) {
      return;
    }
    let cart = JSON.parse(sessionStorage.cart);
    if (!history.state || cart.length > history.state.cartLength) {
      cart.pop();
      sessionStorage.cart = JSON.stringify(cart);
    } else if (cart.length < history.state.cartLength) {
      cart.push(history.state.cartItem);
      sessionStorage.cart = JSON.stringify(cart);
    }
    setup(cart);
  });
  if (!("cart" in sessionStorage)) {
    return;
  }
  let cart = JSON.parse(sessionStorage.cart);
  setup(cart);
});
</script>
<p>Control:
  <a href="?home">home</a> <a href="?shop">shop</a>
  <a href="?item=1">item1</a> <a href="?item=2">item2</a>
</p>
<p>Data: <span id="data"></span></p>
</html>