在前端框架层出不穷的当今时代,页面的变化变得更加具有迷惑性。页面地址变了的话,是否就意味着一定请求了新的页面么?在h5时代之前,答案是肯定的,肯定请求了新的页面。但是在h5时代全面展开后,这个论断就值得怀疑了,眼见不一定为实。页面地址变化了,但是很有可能浏览器并没有请求服务器。那么,在本文中,苏南大叔就描述的是:如何才能不刷新页面,同时还能够改变URL的方式方法。

苏南大叔:前端路由实现:通过pushState()改变URL,同时不刷新页面 - pushstate-hero
前端路由实现:通过pushState()改变URL,同时不刷新页面(图6-1)

本文测试环境:mac/chrome@73.0.3683.103

基本前提

这里描述一下本文中的相关代码的使用前提:那就是不支持file://这样的协议,必须是http(s)://这样的协议。也就是说:双击本地的html文件打开的时候,会报错。这里先埋下个伏笔,因为这个问题,导致了后续的一系列变化。这里就是根源所在。

Uncaught DOMException: Failed to execute 'pushState' on 'History': A history state object with URL 'file:///code/sunan/weui/test/bar.html' cannot be created in a document with origin 'null' and URL 'file:///code/sunan/weui/test/test.html'.
    at file:///code/sunan/weui/test/test.html:12:17

苏南大叔:前端路由实现:通过pushState()改变URL,同时不刷新页面 - history-pushstate-error
前端路由实现:通过pushState()改变URL,同时不刷新页面(图6-2)

另外,本文中的方法,都是定义在jswindow.history对象上面的。所以,大家可以自行脑补上window.history.相关字样。

pushState()replaceState()参数

pushState()replaceState(),因为这两个函数方法的参数,是完全一致的。所以,这里苏南大叔合并讲解描述相关参数。共需要三个参数,分别是: 一个状态对象, 一个标题 (目前被忽略), 一个URL(可选) 。(下方参数文字基本上来自官方说明,略有改动)

  • 状态对象 — 状态对象state是一个JavaScript对象,通过pushState()创建新的历史记录条目。无论什么时候用户导航到新的状态,popstate事件就会被触发,且该事件的state属性包含该历史记录条目状态对象的副本。
  • 标题 — 目前忽略这个参数,但是未来可能会用到。在此处传一个空字符串应该可以安全的防范未来这个方法的更改。或者,你可以为跳转的state传递一个短标题。
  • URL — 该参数定义了新的历史URL记录。注意,调用pushState()后浏览器并不会立即加载这个URL,但可能会在稍后某些情况下加载这个URL,比如在用户重新打开浏览器时。该参数是可选的,缺省为当前URL

本文中的权威文字说明,来自下面的链接:

关于参数,苏南大叔友情提示您:

  • URL也会有跨域相关问题,新的url和当前的url,必须是同一个域下的,才能正常执行。虽然官方写着URL是可选的,但是,大多数情况下,使用最多的确实这个可选的第三个参数,而不是前两个。
  • title参数,目前来看,是没!用!的! 似乎没有啥地方用的到,而且如果你真的需要记录title的话,苏南大叔建议您放到state对象里面。后续的时候,是可以拿到数据的!

pushState()方法

pushState()方法,会在浏览器历史中添加新的记录,而且并不会刷新页面。下面苏南大叔示例一下可能的两种使用方式:

姿势一

三个参数如上所述,大多数情况下,最有可能发生的pushState()的使用姿势是:

window.history.pushState(null, null, "/path.html");

也就是说,忽略statetitle,就传个新的地址就好了。有些诡异吧?

姿势二

那么下面的使用方式,是当初的函数设计人员所期待的使用姿势:

window.history.pushState({foo: "bar"}, "title", "/path.html");

replaceState()方法

replaceState()方法,会替换当前浏览器历史中的记录,也并不会刷新页面。三个参数同上所示,其使用姿势如下:

姿势一

window.history.replaceState(null, null, "/path.html");

姿势二

window.history.replaceState({foo: "bar"}, "title", "/path.html");

效果展示

苏南大叔:前端路由实现:通过pushState()改变URL,同时不刷新页面 - window-history-pushstate
前端路由实现:通过pushState()改变URL,同时不刷新页面(图6-3)

上边这个代码中,先pushState()一次,然后replaceState()一次。那么,第一次真实页面请求,生成了一条历史记录,然后,pushState()生成了第二条历史记录,replaceState()再把第二条历史记录进行了替换。最终的效果是这样的。

苏南大叔:前端路由实现:通过pushState()改变URL,同时不刷新页面 - window-history-pushstate-2
前端路由实现:通过pushState()改变URL,同时不刷新页面(图6-4)

注意:当pushState()replaceState()后,因为url通常发生了变化,而且并没有请求服务器,是个假冒的地址请求过程。如果这个时候,再次f5刷新后,就会真实的页面请求。所以,页面很有可能会发生较大变化!要有这个心理预期!毕竟pushState()replaceState()的地址显示,只是个虚假的演示效果!

特别注意referer来源

这个pushState()replaceState()方法改变页面地址后,这个页面上发出的下一次请求,对应的referer数据也会发生变化。这个不做详细说明,大家看图即可。

苏南大叔:前端路由实现:通过pushState()改变URL,同时不刷新页面 - window-history-pushstate-3
前端路由实现:通过pushState()改变URL,同时不刷新页面(图6-5)

苏南大叔:前端路由实现:通过pushState()改变URL,同时不刷新页面 - window-history-pushstate-4
前端路由实现:通过pushState()改变URL,同时不刷新页面(图6-6)

总结

通过pushState()replaceState()方法改变URL的方法,在一些高级前端框架里面,是非常常见的。由于篇幅限制,那么本文中,苏南大叔主要描述的是URL的变化,这些push进去的数据,如何pop出来,将在下一篇文字中描述,敬请期待。

更多h5新函数应用,可以参见苏南大叔的h5系列文章:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留链接作者。
本站采用创作共用版权协议, 要求署名、非商业用途和相同方式共享。
转载本站内容必须也遵循“署名-非商业用途-相同方式共享”的创作共用协议。
未经许可,规模化镜像抄袭本站内容的行为,将会根据有关法律法规进行维权。
程序如此灵动~》下所有原创文章,如被用于商业用途,请您按规定支付稿费。

 【加群】加入QQ群【175454274】和大家一起讨论这个问题

 【源码】本文代码片段及相关软件,请点此获取

 【绝密】秘籍文章入口,仅传授于有缘之人   h5

本站的忠实读者小伙伴,正在阅读下面这些文章: