pushState:状态对象到底是什么?

75

我已经读了好几遍,说状态对象可能由多个键值对组成,并且与新的历史记录条目相关联。 但是,有人可以举个例子说明状态对象的好处吗?它的实际用途是什么?我想不出为什么不只是输入 {}


1
对我来说,只有在 popstate 事件处理程序中有代码时才有用。这是我第一次使用它,我不需要 popstate 事件处理程序。所以我选择 {},因为它是最合适的值。空对象没有任何问题。 - Sideways S
3个回答

120

来看一个小例子 - 运行示例:

你有一个页面,用户可以选择颜色。每次用户进行选择时,我们都会生成一个新的历史记录条目:

function doPushState (color) {
    var state = {},
        title = "Page title",
        path  = "/" + color;
    
    history.pushState(state, title, path);
};

现在我们先将状态对象留空,把URL设置为颜色名称(不要重新加载页面——该URL不存在,因此会收到404错误)。

现在单击红、绿和蓝各一次。请注意,URL已更改。现在,如果单击“返回”按钮,会发生什么?

浏览器确实会退回到历史记录中,但是我们的页面并没有注意到这一点——URL从“/blue”更改回“/green”,但我们的页面仍然停留在“您选择了蓝色”的位置。我们的页面已经与URL不同步。

这就是window.onpopstate事件和状态对象的作用:

  1. 我们在我们的状态对象中包括所选的颜色
function doPushState (color) {
    var state = { selectedColor: color }, // <--- here
        title = "Page title",
        path  = "/" + color;
    
    history.pushState(state, title, path);
};
  1. 然后我们监听 popstate 事件,以便知道何时需要更新所选颜色,它是这样的:
window.addEventListener('popstate', function (event) {
    var state = event.state;
    
    if (state) {
        selectColor( state.selectedColor );
    }
});

尝试更新示例: 运行 fiddle: 当用户通过浏览历史记录返回时,我们的页面现在会相应地更新。


24
这很好,但是如果我的用户分享了myawesomewebsite.com/blue的Uri给他们的朋友,并说看看这个网站上的蓝色主题有多棒,但是当朋友打开链接时发现主题没有应用,因为他们的浏览器中没有存储状态对象,那么我仍然需要在我的应用程序中使用其他机制来还原访问特定Uri的首次访问者的状态,使得这个功能变得多余,或者我漏掉了什么重要的东西? - Helder Roem
1
@HelderRoem,你说得对,你的应用程序必须提供初始状态,但这并不是多余的,因为有了客户端上的状态,应用程序可以避免每次用户返回/蓝色时访问服务器。 - Vinicius Braz Pinto
7
为什么不直接使用路径,例如 selectColor(location.pathname),而要使用状态对象呢? - ma11hew28
1
@MattDiPasquale 只是为了展示状态对象支持复杂对象,而不仅仅是原始数据类型。 - janfoeh
1
@janfoeh:当我在Firefox v42.0中尝试时,状态被保留了,但URL没有更新。 - Joshua Frank
显示剩余9条评论

2

如果您不想在URL中存储所有数据,它会为您提供此选项。

打开控制台并尝试以下操作:

首先创建一个监听器:

window.addEventListener('popstate', function (event) {    
    console.log(`You first visited this page at ${event.state.time}`)
});

接下来,在控制台中推送状态几次,每次等待一段时间以获取不同的时间(不要复制和粘贴整个块。复制第一行,并将其提交到控制台几次):

history.pushState({time:new Date().getTime()},'','/foo');
history.pushState({time:new Date().getTime()},'','/foo');
history.pushState({time:new Date().getTime()},'','/foo');
history.pushState({time:new Date().getTime()},'','/foo');
history.pushState({time:new Date().getTime()},'','/foo');
history.pushState({time:new Date().getTime()},'','/foo');

现在在浏览器中按下后退按钮并查看控制台。

状态对象可能不是大多数真实世界使用情况的理想选择 - 通常你希望URL完全描述你将要看到的内容。


2

这是一个使用自定义元素和模板,在视图区域分割的渐进式应用程序中维护用户视图和数据状态的特定且前瞻性的用例。

想象一下,您的视图是一个64个方格的网格,在大屏幕上,每个方格的面积为147平方。

URL代表着64个用户ID和相关用户数据。

Web应用程序可以使用用户特定状态数据填充其网格。

在这种我完全相信是未来的用例中,用户不希望共享他或她的个人状态和数据填充的视图部分。

通过使用先前的历史状态及其相关的650k数据,可以使用几种众所周知的排序方法从浏览器历史记录和位置重新组装整个复杂的应用程序,包括状态。

这很酷。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接