操作与监听浏览器历史记录
浏览器提供了几个 api 用于操作/监听浏览器历史记录
onpopstate
对于该需求,首先不难想到的是我们可以找到一种办法来监听页面回退事件。浏览器为我们提供了 onpopstate
事件来监听同一文档中不同的历史记录条目的变更。
只有用户点击浏览器的前进或后退按钮时,或是 JavaScript 执行 history.back()
、history.forward()
、history.go()
方法时,才会触发该事件。
相关详细内容可以参考文档 WindowEventHandlers.onpopstate。
1 | window.addEventListener("popstate", e => { |
需要注意的是,
onpopstate
事件在页面初次加载时并不会被触发。
不过遗憾的是,该事件仅能被监听而不能被阻止。我们需要 pushState
和 replaceState
来辅助我们实现需求。
history.pushState()
浏览器在 history 上为我们提供了一个方法 pushState()
,该方法向当前浏览器会话的历史堆栈中添加一个状态(state)。
1 | history.pushState( state, title, url ); |
该方法接受三个参数:
state
:与本次添加的新历史条目相关联的 state 状态,可以通过history.state
获取。title
:新页面的标题,目前大多数浏览器不支持,传入null
或空字符串即可。url
:新页面的 URL,必须与当前页面同源,否则会抛出异常。不设置时默认为当前文档的 URL。
此状态变更不会触发页面刷新,仅是导致 History
对象发生变化,地址栏会有反应。不会触发 onpopstate
事件,诸如 vue 的生命周期也不会被触发。
同理,设置的 URL
参数为一个新的锚点值时,也不会触发 hashchange
事件。
1 | history.pushState( { temp: true }, null ); |
history.replaceState()
replaceState()
方法与 pushState()
方法类似,但是它是用新的 state 替换当前的历史记录条目,而不是添加一个新的条目。
1 | history.replaceState( { temp: false }, null ); |
实现
通过这两个 api,我们可以确定实现思路。
- 使用
pushState
添加一个当前页面的重复 state,使得浏览器执行回退操作时仅回退掉我们新增的这个 state。 - 使用
onpopstate
监听页面状态变化,执行我们需要的操作。
下面实现一个点击回退关闭弹窗的功能。
1 | const popstateListener = e => { |