History API 使用指北

2023-12-18 20:18
文章标签 使用 api history 指北

本文主要是介绍History API 使用指北,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

https://yeaseonzhang.github.io/2017/03/03/History-API-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8C%97/#more

HTML5 History API,基本上是为了SPA(单页应用)而生。

History API能够在不刷新页面的情况下,通过和url匹配历史堆栈中的数据取出来,这样就能大大减少数据请求,提高用户体验。

其实说实话,能不能提高用户体验,我不知道;在历史记录中切换(前进、后退)真的是如丝般顺滑。

History API 简介

在浏览器环境下,我们可以通过window.history访问我们的浏览器访问历史。
console.png
可能说的有点问题,你只能得到三个值length,scrollRestorationstate。其中只有state的值是我们需要的,接下来会提到。

back()

back()方法相当于点击浏览器的后退按钮。

     
1
     
window.history.back();
forward()

forward()方法相当于点击浏览器的前进按钮。

     
1
     
window.history.forward();
go(n)

go(n)方法允许你在历史session前进或者后退n次。

     
1
2
3
4
5
     
// Go back two entries.
window.history.go(-2);
// Go forward 3 entries.
window.history.go(3);
length

就是我们上文在浏览器得到的length属性。

下面就是我们的重头戏,HTML5 History API,上面的属性方法只是简单的热身,你可能不需要热身。

HTML5 History API

HTML5 History API包含两个方法和一个事件。

  • pushState()
  • replaceState()
  • popstate

在详细介绍之前,我们先来看看各个浏览器对于HTML5 History API支持情况。

caniuse.com

caniuse.com

可以说现在主流的浏览器对于HTML5 History API支持都是很好的,不过也要考虑向下兼容。

     
1
2
3
4
5
     
if (!!history.pushState) {
// support
} else {
// dont support
}
pushState()
     
1
     
pushState(state, title, url)
  • state: 传递给history.state
  • title: 似乎浏览器还没有很好支持,传null就好
  • url: 可选,这个参数会改变你的浏览器url

这个方法是在浏览器堆栈历史中push一条新的数据,然后将指针指向这条数据。

replaceState()
     
1
     
replaceState(state, title, url)

replace()方法与pushState()方法类似,主要是能够替换更新pushState()state数据。

参数描述详见pushState()的描述。

popstate事件

当用户点击浏览器的前进/后退按钮,popstate事件会被调用。

     
1
2
3
4
5
6
7
8
     
window.addEventListener('popstate', function (event) {
// update the page content
});
// or
window.onpopstate = function (event) {
// update the page content
}

以上就把History API简略介绍了一下,详细说明请访问MDN。

手把手实战

需求分析

网上也不乏介绍H5 History API应用的文章,大概也都是比较简单的Demo。

http://html5demos.com/history

http://html5demos.com/history

点击链接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文件夹。

file system

file system

如上图,该目录下有文件和文件夹,点击文件会直接在浏览器打开该文件或者下载,点击文件夹会进入该文件夹,页面显示该文件夹的内容。

这样就需要我们把urlhash值动态改变,然后根据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
20
     
HTTP/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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
     
<div class="file-list">
<div class="weui-cells">
<a v-if="fileList.length" v-for="item in fileList" href="javascript:;" class="weui-cell weui-cell_access">
<!-- Dir -->
<div v-if="item.isdir">
<div class="weui-cell__hd">
<span class="icon-size an-folder"></span>
</div>
<div class="weui-cell__bd" @click="openDir(item)">
<p>{{ item.name }}</p>
</div>
</div>
<!-- File -->
<div v-else>
<div v-else class="weui-cell__hd">
<span class="icon-size an-file"></span>
</div>
<div class="weui-cell__bd" @click="openFile(item)">
<p>{{ item.name }}</p>
</div>
</div>
</a>
<a v-if="!fileList.length" class="weui-cell weui-cell_access" href="javascript:;">
<div class="weui-cell__bd">
<p>No such file or directory</p>
</div>
</a>
</div>
</div>

将文件夹和文件分成两类进行渲染,绑定不同的点击函数,并传递参数为文件(夹)名,前面的前后端API也提示我们是通过name进行请求。

JS
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
     
(function (exports) {
exports.app = new Vue({
el: '.file-list',
data: {
haveFile: true,
fileList: [],
},
mounted: fucntion () { // 挂载之后,自动执行
this.$nextTick(function () {
this.initGetfile();
})
},
methods: {
initGetfile: function () {
var _this = this;
var hash = _this.getHash();
var url = '/api/v1/fileproxy/' + hash;
axios.get(url)
.then(function (res){
_this.fileList = res.data.data;
// replaceState()
history.replaceState(_this.fileList, null);
if (!res.data.data.length) {
_this.haveFile = false;
} else {
_this.haveFile = true;
}
})
},
openDir: function (item) {
var _this = this;
_this.loadFile = true;
var hash = _this.getHash();
var url = '/api/v1/fileproxy/-/' + hash + item.name +'/';
axios.get(url)
.then(function (res) {
_this.fileList = res.data.data;
_this.loadFile = false;
var newUrl = window.location.href + item.name + '/';
// pushState()
history.pushState(_this.fileList,null, newUrl);
if (!res.data.data.length) {
_this.haveFile = false;
} else {
_this.haveFile = true;
}
});
},
openFile: function (item) {
var _this = this;
var hash = _this.getHash();
var url = '/api/v1/fileproxy/-/' + hash + item.name;
window.open(url);
},
getHash: function () {
var hash = window.location.hash.substr(1);
if (hash.substr(-1) != '/') {
hash += '/';
}
return hash;
},
}
});
window.onpopstate = function (e) {
console.log('pop state');
console.log('state', JSON.stringify(e.state));
if (e.state != null) {
app.fileList = e.state;
} else {
window.location.reload();
}
}
})(window);

以上就是我完成基本功能的源码,添加History API到项目中并没有做太多改动:

  1. 增加pushState()repalceState()函数

  2. 替换原有的hashchange事件为popstate事件。

结语

本没有对源码做过多的分析,因为可能需求不一样采取的处理方法也不一样,我只是提供一个#abc/def...这种hash值比较复杂需求的一种实现。

希望能够对你有所启发,也是现学现卖,如有不妥之处,望指正。

这篇关于History API 使用指北的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/509646

相关文章

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery

使用Python绘制蛇年春节祝福艺术图

《使用Python绘制蛇年春节祝福艺术图》:本文主要介绍如何使用Python的Matplotlib库绘制一幅富有创意的“蛇年有福”艺术图,这幅图结合了数字,蛇形,花朵等装饰,需要的可以参考下... 目录1. 绘图的基本概念2. 准备工作3. 实现代码解析3.1 设置绘图画布3.2 绘制数字“2025”3.3

Jsoncpp的安装与使用方式

《Jsoncpp的安装与使用方式》JsonCpp是一个用于解析和生成JSON数据的C++库,它支持解析JSON文件或字符串到C++对象,以及将C++对象序列化回JSON格式,安装JsonCpp可以通过... 目录安装jsoncppJsoncpp的使用Value类构造函数检测保存的数据类型提取数据对json数

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

springboot整合 xxl-job及使用步骤

《springboot整合xxl-job及使用步骤》XXL-JOB是一个分布式任务调度平台,用于解决分布式系统中的任务调度和管理问题,文章详细介绍了XXL-JOB的架构,包括调度中心、执行器和Web... 目录一、xxl-job是什么二、使用步骤1. 下载并运行管理端代码2. 访问管理页面,确认是否启动成功

使用Nginx来共享文件的详细教程

《使用Nginx来共享文件的详细教程》有时我们想共享电脑上的某些文件,一个比较方便的做法是,开一个HTTP服务,指向文件所在的目录,这次我们用nginx来实现这个需求,本文将通过代码示例一步步教你使用... 在本教程中,我们将向您展示如何使用开源 Web 服务器 Nginx 设置文件共享服务器步骤 0 —

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

Golang使用minio替代文件系统的实战教程

《Golang使用minio替代文件系统的实战教程》本文讨论项目开发中直接文件系统的限制或不足,接着介绍Minio对象存储的优势,同时给出Golang的实际示例代码,包括初始化客户端、读取minio对... 目录文件系统 vs Minio文件系统不足:对象存储:miniogolang连接Minio配置Min

使用Python绘制可爱的招财猫

《使用Python绘制可爱的招财猫》招财猫,也被称为“幸运猫”,是一种象征财富和好运的吉祥物,经常出现在亚洲文化的商店、餐厅和家庭中,今天,我将带你用Python和matplotlib库从零开始绘制一... 目录1. 为什么选择用 python 绘制?2. 绘图的基本概念3. 实现代码解析3.1 设置绘图画