前言
项目开发时候,经常会涉及到关于浏览器历史记录的一些操作,比如当前页面点击微信返回按钮后跳转到某一特定页面等等。吃过这个苦,方之水之深,水深不可怕,关键在于勤。
如何生成一条历史记录
- 简单粗暴的方法,直接在当前页面的地址栏中输入地址
- 点击页面中有a标签的href
- 执行location.href = ‘xxx’(location.replace(‘xxx’)生成一条记录取代当前指针所指向的记录)
- 表单提交跳转(注意只能跳到当前窗口)
- 使用pushState方法可以不刷新页面就可以生成一条历史记录,页面URL发生改变
简而言之,只要当页面的URL改变时,就会生成一条历史记录。在IE8及更高的版本中、Opera、Firefox、Chrome、Safari3及更高的版本中改变hash也会生成一条历史记录。
浏览器对历史记录的管理
栈
历史记录在浏览器中以栈的形式进行管理,每次增添的历史记录都会在栈的最顶端,以谷歌浏览器为例
html代码:
<div>
<a href="demo1.html">demo1</a>
</div>
<div>
<!--通过location.href="demo2.html"改变页面地址:-->
<button type="button" onclick="changTo(2);">href="demo2.html"</button>
</div>
<div>
<form action="demo3.html" method="get" class="dib"><button type="submit" >demo3.html</button></form>
</div>
<div>
<!--通过pushState来改变页面地址:-->
<button type="button" onclick="push4()">pushState"demo4.html"</button>
</div>
js代码:
function changTo(index) {
location.href = 'demo' + index + '.html';
}
function push4() {
history.pushState('hello', '', '/demo4.html')
}
点击demo1,demo2,demo3,demo4,然后再点击demo3,demo2,demo1生成的历史记录如下图:
使用history API操作栈指针来获取历史页面
指针所在的位置会获取当前页面的state,
history.back() : 返回上一页
history.forword() : 跳转到前一页
history.go(n) : n可以为正数也可为负数,代表当前指针是向前移动还是向后移动几个位置。如果n大于或小于历史记录的数目时,指针不会发生任何变化。
下面图片的操作步骤为:先back() => go(-2) => go(-2) => go(2)
如果此时在demo3的位置点击demo1,历史记录栈会如下所示:
历史记录都是插入在栈指针所在位置的后面,前面的记录会被自动删除
限制
历史记录超过了浏览器限制的最大条数(比如chrome、firfox为50条,IE超过了100),栈顶进入一条历史记录,则栈的底端移出去一条。
单页面应用中如何实现路由切换
HTML5推出的history API
三种方法:pushState replaceState onPopState
pushState(state, title, URL)
1. state: 代表一个Javascript对象,在创建对象的时候设置,可以在onpopstate和history对象中获取。(we impose a size limit of 640k characters on the serialized representation of a state object.)
2. title: Firefox目前忽略这个参数,你可以给你的state设置一个小标题
3. URL: 压人记录栈中URL,可选,不指定则视为当前URL。
- 当执行pushState这个方法的时候不会去加载这个URL,但是会改变地址栏中的url。当重新加载这个页面时,URL是push进去的参数。
- URL必须是同源链接
replaceState(state, title, URL)参数和pushState一样,会替代当前指针指向的历史记录
onPopState: 当指针在历史记录栈中已有的位置上移动时会触发,且指定的地址仍然在当前dom中。pushState和replaceState的操作不会触发这个事件
MDN解释:
A popstate event is dispatched to the window every time the active history entry changes between two history entries for the same document.
The popstate event is only triggered by doing a browser action such as clicking on the back button (or calling history.back() in JavaScript).
And the event is only triggered when the user navigates between two history entries for the same document.
1. 方法一
生成一条历史记录
window.history.pushState('{key: 1586}', '', '/demo1.html')
切换页面
window.addEventListener('popstate', e => {
const obj = e.state // 可获取栈指针指向的记录state
// dosometing
})
异步传参
可根据state来传参
根据hash实现,hashchange来捕捉路由的变化
2.方法二
生成一条历史记录
function getHash() {
// We can't use window.location.hash here because it's not
// consistent across browsers - Firefox will pre-decode it!
const href = window.location.href
const index = href.indexOf('#')
return index === -1 ? '' : href.slice(index + 1)
}
function pushHash (path) {
window.location.hash = path
}
function replaceHash (path) {
const i = window.location.href.indexOf('#')
window.location.replace(
window.location.href.slice(0, i >= 0 ? i : 0) + '#' + path
)
}
切换页面
hashchange监听后退和前进操作
window.addEventListener('hashchange',function(){
// dosometing
})
异步传参
function getParams(){
var hashArr = location.hash.split("?"),
hashName = hashArr[0].split("#")[1],//路由地址
params = hashArr[1] ? hashArr[1].split("&") : [],//参数内容
query = {};
for(var i = 0;i<params.length ; i++){
var item = params[i].split("=");
query[item[0]] = item[1]
}
return {
path:hashName,
query:query
}
}