history API
history API
history对象表示当前窗口首次使用以来用户的导航历史记录,history对象不会暴露用户已经访问过的URL,但是会提供一些API来实现URL的前进和后退。
URL跳转
window.history 提供三个API来实现页面URL的跳转:
- go():传递一个整数,正整数表示向前跳多少,负整数表示向后跳多少。 
- forward():向前跳一页,类似浏览器的前进按钮。 
- back(): 向后跳一页,类似浏览器的回退按钮。 
例如:
window.history.back();
// 等同于
window.history.go(-1);
window.history.forward();
// 等同于
window.history.go(1);还可以通过查看长度属性的值来确定的历史堆栈中页面的数量:
window.history.length;
可以用这个属性来判断你的页面是否是用户第一个打开的页面:
if(window.history.length === 1){
	// ...
}更新URL但不进行跳转
history API
history.pushState
随着前端技术的不断发展,传统的URL跳转API已经不能在满足我们的需求了,例如在SPA应用中,页面跳转本质上并非是向服务器请求新的页面,而是通过JavaScript、DOM API等技术直接由前端改变页面内容,这个时候就需要一种能够实现可以更新URL,但是不需要进行跳转的技术。
HTML5 引入了 history.pushState()和 history.replaceState()方法,它们分别可以添加和修改历史记录条目。他们和前面讲到的go、replace等API很相似,但是最大的区别是这两个方法只会改变URL,不会向服务器发送页面请求。Vue-Router的history模式底层就是使用的这种方法。
history.pushState()和 history.replaceState()方法接收三个参数:
- 状态对象:状态对象 state 是一个 JavaScript 对象,通过 pushState () 创建新的历史记录条目。无论什么时候用户导航到新的状态,popstate 事件就会被触发,且该事件的 state 属性包含该历史记录条目状态对象的副本。状态对象的大小是有限制的,通常是500KB~1MB以内,如果超过这个限制就会报错。如果你需要更大的空间,建议使用 - sessionStorage以及- localStorage。
- 标题,目前没有实现,可以传个空字符串。 
- URL:要跳转的URL,可以是相对路径URL,也可以是一个绝对路径URL,但是新 URL 必须与当前 URL 同源。 
window.history.pushState({a: 1}, '', '/')history.pushState()和 history.replaceState()方法的区别在于前者是新建一个历史记录,而后者是替换当前的历史记录。
window.onpopstate
每当活动的历史记录项发生变化时, popstate事件都会被传递给 window 对象。如果当前活动的历史记录项是被 pushState创建的,或者是由 replaceState改变的,那么 popstate事件的状态属性 state会包含一个当前历史记录状态对象的拷贝。
注意 调用
history.pushState()或者history.replaceState()不会触发popstate事件。popstate事件只会在浏览器某些行为下触发,比如点击后退按钮(或者在JavaScript 中调用history.back()方法)。即,在同一文档的两个历史记录条目之间导航会触发该事件。
history.state
history.state可以获取到当前历史记录的状态对象,如果当前没有使用过pushState或者replaceState,则该属性返回null。
刷新
使用history.pushState和history.replaceState 时需要格外注意,当用户点击刷新按钮时页面重新加载,此时浏览器仍然会发送当前URL的http请求到服务器,因此使用这两个API时需要考虑到服务端对这些GET 请求的处理,你可以
- 在服务端为每个URL设置一个真实的URL地址,返回对应的页面。 
- 将所有URL都指向index.html文件(SPA) 
如果你用过vue-router的history模式,那么你应该就有过这种体验,如果你没有配置好服务端,那么当你在某个URL刷新时,会得到一个404的页面,而解决的方法是在服务端为该应用的所有路径都配置返回index.html文件,这背后的原理就是其底层使用的正是history.pushState 。
示例
下面示例中实现了三个按钮,其中pushState每点击一次都会执行一次history.pushState({a: a}),变量a初始等于0,每次使用都会+1,点击replaceState会执行history.replaceState({a: a}) ,点击back按钮时会执行history.back()函数以实现历史记录的回退,这会触发popState事件,此时你应当可以在控制台看到事件对象(event)。
https://codesandbox.io/s/history-state-4hqci3?file=/index.html
location.hash
另一种能更新URL但不会进行跳转的方法是使用window.location.hash 。window.location 对象保存了当前URL中的各项信息,例如hostname、protocol、port和hash等属性,其中hash属性中保存了当前URL以’#’开头的URL片段,并且更新这部分片段浏览器不会发送新的http请求。
location.hash的一个应用在于页内跳转锚点,例如
<a href="#a">跳转到id=a的元素</a>当点击该链接时,页面会跳转到对应id的元素上,但是不会发送请求重新加载页面。
window.location.hash 属性可以被修改,并且修改操作会将修改后的URL添加到历史记录中,以便能够实现前进和后退。
window.location.hash = '/s/1'和history API类似,location.hash也具有相应的事件监听器:hashchange。
window.addEventListener('hashchange',function(e){console.log(e ) })要注意的是,和前面的popstate事件一样,当修改window.location.hash时并不会触发hashchange事件,只有当前进或者后退,即在两个历史记录间切换时才会触发hashchange事件。
location.hash和history.push的区别
从某种程度来说,调用 pushState() 和 window.location = "#foo"基本上一样,他们都会在当前的 document 中创建和激活一个新的历史记录。但是 pushState() 有以下优势:
- 新的 URL 可以是任何和当前 URL 同源的 URL。但是设置 - [window.location](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/location)只会在你只设置锚的时候才会使当前的 URL。
- 非强制修改 URL。相反,设置 - window.location = "#foo";仅仅会在锚的值不是 #foo 情况下创建一条新的历史记录。
- 可以在新的历史记录中关联任何数据。 - window.location = "#foo"形式的操作,你只可以将所需数据写入锚的字符串中。
最后更新于