HTML5 History API,基本上是为了SPA(单页应用)而生。
History API能够在不刷新页面的情况下,通过和url匹配历史堆栈中的数据取出来,这样就能大大减少数据请求,提高用户体验。
其实说实话,能不能提高用户体验,我不知道;在历史记录中切换(前进、后退)真的是如丝般顺滑。
History API 简介
在浏览器环境下,我们可以通过window.history访问我们的浏览器访问历史。
可能说的有点问题,你只能得到三个值length,scrollRestoration和state。其中只有state的值是我们需要的,接下来会提到。
back()
back()方法相当于点击浏览器的后退按钮。
1 | window.history.back(); |
forward()
forward()方法相当于点击浏览器的前进按钮。
1 | window.history.forward(); |
go(n)
go(n)方法允许你在历史session前进或者后退n次。
1 | // Go back two entries. |
length
就是我们上文在浏览器得到的length属性。
下面就是我们的重头戏,HTML5 History API,上面的属性方法只是简单的热身,你可能不需要热身。
HTML5 History API
HTML5 History API包含两个方法和一个事件。
pushState()replaceState()popstate
在详细介绍之前,我们先来看看各个浏览器对于HTML5 History API支持情况。
可以说现在主流的浏览器对于HTML5 History API支持都是很好的,不过也要考虑向下兼容。
1 | if (!!history.pushState) { |
pushState()
1 | pushState(state, title, url) |
state: 传递给history.statetitle: 似乎浏览器还没有很好支持,传null就好url: 可选,这个参数会改变你的浏览器url
这个方法是在浏览器堆栈历史中push一条新的数据,然后将指针指向这条数据。
replaceState()
1 | replaceState(state, title, url) |
replace()方法与pushState()方法类似,主要是能够替换更新pushState()的state数据。
参数描述详见pushState()的描述。
popstate事件
当用户点击浏览器的前进/后退按钮,popstate事件会被调用。1
2
3
4
5
6
7
8window.addEventListener('popstate', function (event) {
// update the page content
});
// or
window.onpopstate = function (event) {
// update the page content
}
以上就把History API简略介绍了一下,详细说明请访问MDN。
手把手实战
需求分析
网上也不乏介绍H5 History API应用的文章,大概也都是比较简单的Demo。
点击链接first、second、third..,url会改变为http://html5demos.com/history#fitst,http://html5demos.com/history#second…
获取不同#first,#second的数据,渲染页面中的数据。具体实现源码。
本文,我想介绍的不是这种demo,而是比较实际的项目开发。
实现一个文件系统的浏览页面,通过url哈希值#...记录文件夹的路径。
例如,www.demo.com/filesystem.html#abc/就是根目录下abc文件夹;www.demo.com/filesystem.html#abc/def/代表abc文件夹下的def文件夹。
如上图,该目录下有文件和文件夹,点击文件会直接在浏览器打开该文件或者下载,点击文件夹会进入该文件夹,页面显示该文件夹的内容。
这样就需要我们把url的hash值动态改变,然后根据hash值确定所在文件路径向后台获取资源。
前后端接口API
显示目录
请求:1
GET /api/v1/fileproxy/pub/abc/ HTTP/1.1
响应:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"error": 0,
"errormsg": "success",
"data": [
{
"name": "a.txt",
"size": 1234,
"time": 1235153531,
"isdir": false,
},
{
"name": "a.txt",
"size": 1234,
"time": 1235153531,
"isdir": false,
}
]
}
打开/下载文件
请求:1
GET /api/v1/fileproxy/pub/abc/a.txt HTTP/1.1
从后端获取到的文件信息包括name文件(夹)名,size大小,time修改时间,isdir是否是文件夹。
流程
initGetfile()openDir(str)window.onpopstate
initGetfile()函数,首次进入或者刷新页面自动执行该函数,渲染文件列表。
openDir(str)函数,当点击文件夹时调用该函数,获取新的文件列表。
window.onpopstate也就是popstate事件。
在没有使用History API时,是通过hashchange事件来触发文件列表的更新,这就导致每一次前进后退都会发起一次ajax请求,没有把之前请求过的数据进行缓存,影响用户体验。
对了在此要声明一下,
psuhState()和replaceState()不会触发hashchange事件
怎么理解呢,就是当你通过psuhState()和replaceState()的第三个参数url对于hash值有更改的时候,也不会触发hashchange事件。
Chrome 和 Safari浏览器在重载页面的时候会触发popstate事件,Firefox浏览器不会。
重头戏
下面将会贴上我的代码,使用Vue2 和 axios实现。
HTML
1 | <div class="file-list"> |
将文件夹和文件分成两类进行渲染,绑定不同的点击函数,并传递参数为文件(夹)名,前面的前后端API也提示我们是通过name进行请求。
JS
1 | (function (exports) { |
以上就是我完成基本功能的源码,添加History API到项目中并没有做太多改动:
增加
pushState()和repalceState()函数替换原有的
hashchange事件为popstate事件。
结语
本没有对源码做过多的分析,因为可能需求不一样采取的处理方法也不一样,我只是提供一个#abc/def...这种hash值比较复杂需求的一种实现。
希望能够对你有所启发,也是现学现卖,如有不妥之处,望指正。