浏览器历史堆栈管理
Opened this issue · 0 comments
前言
先说背景,在商品列表中,每一个商品都有详情入口,跳转到新的页面后,列表页会被销毁。
再说这样一个场景,这个列表很长,浏览到列表中部时,进入某个商品详情页,再返回时,列表页就刷新了,列表回到了顶部。这样体验很不好...... 然后需求就很明确了,如何在从详情页回到列表页之后,回到原始浏览位置,甚至列表页保持原样。
这里参考对话框浮层的做法,用一个覆盖全屏的浮层,利用History的历史堆栈,使其拥有页面的基本功能(前进、后退)。
History API
借用栈和指针的概念介绍一下History的接口,文档中并未说明Histroy是个堆栈,这里只是借用一下
pushState
history.pushState(stateObject, title, url) 包括三个参数。
-
stateObject
用于存储该url对应的状态对象,该对象可在onpopstate
事件中获取,也可通过history.state
获取。 -
title
是标题,目前浏览器并未实现。 -
url
则是设定的url。一般设置为相对路径,如果设置为绝对路径时需要保证同源。若不传则默认为当前url。
history.pushState()向栈中压入一个指定url的记录,然后将指针指向这个记录,并截去这个记录之后的所有记录,使之成为栈顶(如下图);无副作用的将当前url更改为传入的url(修改hash值也不会触发hashchange事件)
replaceState
与pushState参数相同,含义也相同。唯一的区别在于replaceState是仅仅是将当前指针指向的记录更改为传入url。如上图
back、forward和go
这三个方法作用仅在于,移动指针并触发popstate事件,并不会改变histroy的长度(histroy.length)。
onpopstate
在不改变document的前提下,一旦当前指针改变(包括浏览器的前进后退)就会触发onpopstate事件。并在指针修改之后才触发。监听这个事件会传入一个对象,包含指针指向的记录信息。
Talk is cheap, Show me the code
请看这里👉code
详情页不仅要从某个页面的商品点击进入,更要通过url作为独立的页面展示,所以详情页有两种存在形式:
- 依附于某个页面,作为浮层的形式存在
- 作为一个独立的页面存在(当然这里页面还是SPA中的页面的意思,由router控制)
- 向历史记录堆栈中压入一条记录
- 监听popstate事件
- 唤起详情页(浮层形式)
这里存在一个问题,当唤起页面之后,刷新或复制链接发送给人,该如何唤起浮层呢。前文提到pushState可无副作用的修改url,我们只需将url修改成和独立页面的详情页的url一样即可。这样刷新还是复制链接都将跳转到路由层的详情页,从而免去唤起浮层。
再看这段:
重点在于这个判断条件,上文提到popstate事件在指针移动之后触发,并传入一个对象,包含了指针指向的记录的信息。若在浮层页之后有其他不是我们预期的行为移动了指针,触发popstate事件,就会把浮层页关闭了。所以一定这里要确保指针移动后不是指向浮层页的记录,再关闭浮层。
以上。