客户端的存储相当于给浏览器赋予了记忆功能。同一个站点的数据是如何共享数据的,一个页面填写的表单如何显示在另一个页面中,页面关闭或浏览器退出,打开还能重新显示原来的页面,这些都可以依靠浏览器的存储功能来实现。
一、Web存储
1、localStorage和sessionStorage
基本代码实现
两个属性都代表同一个Storage对象,一个持久化关联数组,数组使用字符串来索引,储存的值也是字符串的形式。localStorage和sessionStorage的区别在于储存的有效期和作用域不同,储存形式和api是一样的。
一般使用形式
localStorage.name = '曾田生'; // 储存字符串
var name = localStorage.name; // 获取存储信息
当储存数字时会自动转化成字符串,所以在取值是需要手动转换
localStorage.age = 666;
var age = parseInt(localStorage.age);
日期也一样
localStorage.time = (new Date()).toUTCString();
var time = new Date(Date.parse(localStorage.time));
咱们常用的json数据
localStorage.jsonData = JSON.stringify(data);
var jsonData = JSON.parse(localStorage.jsonData);
存储API
localStorage和sessionStorage除了可以通过上面的设置属性来存储值和通过查询属性来取值外,还有一套API操作数据。
下面就一个简单例子来说明:
// 存取值
localStorage.setItem('name','曾田生');
var name = localStorage.getItem('name');
// 获取 key - value
var keyName = localStorage.key(0);
var value = localStorage.getItem(keyName);
// 删除指定值
localStorage.removeItem('name');
// 清空 localStora
localStorage.clear();
存储事件
localStorage和sessionStorage 存储发生变化就会触发存储事件,事件采用广播的机制,会在同样站点的作用域范围内发送消息。注意的是 localStorage和sessionStorage 的区别在于作用域的不同,所以事件触发的窗口也有区别,作用域在下面小节会讲到,还有一点是在发生存储数据改变的窗口上是不会触发该存储事件的。
下面一个小例子:
我打开了两个页面 index.html
btn.addEventListener('click', function () {
localStorage.name = '曾田生'; // 储存字符串
var name = localStorage.name; // 获取存储信息
})
index2.html 做存储事件监听:window.addEventListener
window.addEventListener("storage", function(e){
console.log(e);
console.log("oldValue: "+ e.oldValue + " newValue:" + e.newValue);
});
点击 index.html 的 button 后 index2.html打印出如下消息
存储有效期和作用域
localStorage和sessionStorage 的使用和api是相同的,但它们的有效期和作用域是有区别的。
(1)、localStorage
localStorage 的作用域限定在文档源级别,什么意思呢,协议、主机名、端口三者一样那就是同一文档源,同源的文档间共享同样的localStorage数据。比如如下:
http://www.example.com // 协议:http;主机名:www.example.com
https://www.example.com // 不同协议
http://demo.example.com // 不同 主机名
http://www.example.com:8000 // 不同端口
以上只有不满足同源要求,即使在同一台服务器也不能共享localStorage数据。
(2)、sessionStorage
首先 sessionStorage的作用域也是限定在同源里面,并且sessionStorage的作用域还被限定在窗口中。
比如:
A.html
<a href="B.html">B.html</a>
<script type="text/javascript">
sessionStorage.name = 'zengtiansheng'
console.log(sessionStorage.name);
</script>
点击 A.html 的 <a 标签 能打开 B.html
<script type="text/javascript">
console.log(sessionStorage.name);
// 打印出 zengtiansheng
</script>
但是不通过 A.html 的 <a 标签 能打开 B.html ,而是直接打开 B.html 打印出的日志是 undefined
二、cookie
cookie最早是设计为被服务器所用,cookie数据会自动在web服务器和web浏览器之间传输的,所用服务器可读取来着客户端cookie的值并修改其cookie值。
或许你对自动传输这个概览不是很理解,先看一个例子:
设置cooike:
window.onload = function () {
document.cookie = 'user = zss';
document.cookie = 'age = 233';
}
接着想服务端随便发送一个GET请求:
app.get('/getAge', function (req, res) {
console.log('-------------cookie---------');
console.log(req.headers);
console.log('-------------cookie---------');
res.send('Hello World');
});
var server = app.listen(8081, function () {
console.log("应用实例,访问地址为 http://%s:%s", host, port)
});
服务端接受GET请求咱们打印出响应头看看:
-------------cookie---------
{ host: '127.0.0.1:8081',
connection: 'keep-alive',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'accept-encoding': 'gzip, deflate, sdch, br',
'accept-language': 'zh-CN,zh;q=0.8',
cookie: 'Hm_lvt_800f0f35f4557a08958a37aa22f2d2b0=1485226901; user=zss; age=233',
'if-none-match': 'W/"b-sQqNsWTgdUEFt6mb5y4/5Q"' }
-------------cookie---------
有没有看到虽然咱们客户端随便发送个请求,客户端就会把设置的 cookie 给带了过去,cookie数据会自动在web服务器和web浏览器之间传输
1、保存和读取cookie
保存 cookie
设置cookie非常简单,只需将cookie属性设置为一个字符串形式的值。如
document.cookie = 'name='+encodeURIComponent('曾田生');
为什么需要 encode值呢,因为cookie的 名/值 中的值是不允许包含分号、逗号和空白符的。所用一般在存值得使用会采取相应的 encode,同样读取值得使用也需要 decode 一下。
上面一简单 名/值 的形式储存cookie数据的有效期只在当前 Web 浏览器的会话内,一但用户关闭浏览器cookie数据就丢失。
所以还可以给 cookie 添加日期和一些其他信息,只需以逗号分开:
document.cookie = 'name='+encodeURIComponent('曾田生')+
';max-age='+60*60+ // 设置有效期 60*60就是1小时有效
';path='+'path'+ // 设置路径
';domain='+'domain'+
';secure='+'secure';
读取 cookie
读取cookie 其返回值是一个字符串,所以下面写个了方法将字符串的 cookie 转成对象的形式:
function getCookie(){
var cookie = {};
var all = document.cookie;
if(all === ''){
return cookie;
}
var list = all.split('; ');
for(var i= 0,len=list.length;i<len;i++){
var ck = list[i];
var p = ck.indexOf('=');
var name = ck.substring(0,p);
var value = ck.substring(p+1);
value = decodeURIComponent(value);
cookie[name] = value;
}
return cookie;
}
2、cookie 的作用域
cookie的作用域是通过文档源和文档路径来确定的。该作用域是通过文档源和文档路径来确定,也可通过cookie的 path和domain属性来配置不同的作用域。
默认情况
默认情况下在下面页面创建了cookie,那么该cooki对页面同目录或子目录是可见的,如下页面创建了cookie:
http://www.example.com/src/index.html
那么该cookie对下面的页面是可见的:
http://www.example.com/src/index2.html
http://www.example.com/src/A/index.html
http://www.example.com/src/B/C/index.html
对下面页面不可见:
http://www.example.com/index3.html
http://www.example.com/A/index.html
path 改变作用域
前面也讲了,默认情况下哪个页面创建了cookie,那么该cooki对页面同目录或子目录是可见的。那要是我们有个需求是:用户在这个页面添加的表单数据在整个网站都可以用(包括它的父级页面)。
那就需要利用 cookie的path 属性了,如:
cookie是在以下页面所创建的:
http://www.example.com/A/B/index.html
修改 path:
document.cookie ='path='+'/A'; // 设置路径
本来只能在 /B 或 /B 以下的目录能访问到cookie ,现在 是在 /A 即以下目录能访问cookie 了!
进一步修改path:
document.cookie ='path='+'/'; // 设置路径
现在是该cookie对任何 http://www.example.com 这台服务器可见了!
发现点:把cookie的 path 设为 '/' 等于前面所说的 localStorage 拥有相同的作用域了!
domain 修改作用域
还有一种需求是:一些业务需要,A.example.com 域下的服务器想要读取 B.example.com 域下的服务器设置的cooike值,那该怎么办呢,domain它说它能解决:
document.cookie ='path='+'/' // 设置路径
+';domain='+'.example.com' // 设置domain
那么,cookie就能在 example.com 下的任何其他服务器可见了。
cooike 的 secure 属性
cookie 默认是以不安全的形式(通过普通的,不安全的 HTTP 链接)传递的。
设置 secure:
document.cookie ='secure='+true'
那么 cookie 只能在 HTTPS 或其他安全协议链接的时候它才能传递。
三、离线Web储存
localStorage和sessionStorage 只是保存了 web应用程序相关的数据,要是我们想要保存比如图片、
css 、js等文件 ,是否能做到呢。
1、appcache
HTML5新增了‘应用程序缓存’,配合一份缓存清单,就可实现比如图片、css 、js等文件的缓存,甚至做到
离线web应用。
下面以一个例子讲述:
项目文件:
index.html: 在 <html 标签添加 app.appcache 配置文件
<!DOCTYPE html>
<html manifest="app.appcache">
<head>
<meta charset="UTF-8">
<title>appcache test</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="img-1"></div>
<img class="img-2" src="img/img_2.png" alt="img2">
<div class="text" id="text"></div>
<script src="index.js"></script>
</body>
</html>
其中 style.css
body{
background: #eb5f6f;
}
.img-1{
width: 100px;
height: 100px;
background: url("img/img_1.png") no-repeat;
background-size: 100%;
}
.img-2{
width: 100px;
height: 100px;
}
index.js
window.onload = function () {
document.getElementById('text').innerHTML='appcache 测试';
}
app.appcache 配置文件:
CACHE MANIFEST
# version 1.0.1
index.js
style.css
img/img_1.png
img/img_2.png
NETWORK:
*
FALLBACK:
./index.html ./404.html
第一次加载页面:
可以看到资源被缓存了
再次刷新页面:
NetWork这边的 size 显示 form disk cache ,并且咱们的网页,css js 和图片都是正常显示的,但这时是从磁盘上获取的文件,而不是网络上。
有了上面的例子,咱们来介绍介绍 app.appcache 配置文件:
CACHE MANIFEST
清单文件必须以 CACHE MANIFEST 开头,其余一行一个 url,指向相对 .appcache 路径的资源,上面也看到了,资源可以是 .css .js 图片或其他。
NETWORK
标识了URL的资源从不缓存
NETWORK:
*
则表示任何不在清单的资源,浏览器都从网络加载。
FALLBACK
这个标签底下每行都包含两个URL ,比如:
FALLBACK:
./index.html ./404.html
第一个Url 表示匹配到的资源不被缓存起来,会去网络加载,第二个Url表示当第一个Url从网络加载的资源出错,那就加载第二个Url的资源来显示。
2、j慎用 appcache
虽然看了上面 appcache 感觉挺不错的样子,但不幸的是官方已经不推荐使用,这一套缓存在实际项目中纯在很多缺陷,比如:
1、当缓存清单缓存了文件,文件有改动,但用户访问的资源还是从缓存中读取,必须修改 appcache缓存文件,当用户
再次访问网页的时候缓存文件采取从新从服务器拉去资源,但糟糕的是只是去服务端拉取资源而已,用户访问的还是原来的缓存,需要用户再次刷新页面才能从缓存中读取新的资源。
这也是为什么我在
CACHE MANIFEST
# version 1.0.1
加了个 version 的原因,因为你改的任何 appcache 都会触发清单文件重新去服务器拉取资源
2、如果更新的资源中有一个资源更新失败了,将导致全部更新失败,将用回上一版本的缓存。这更坑
3、manifest本身的编写要求比较严格,要注意换行跟路径文件名之类的问题。不然缓存将无效。
等等,所以慎用,慎用
总结:
介绍了几种浏览器存储方式,希望对你所有帮助,起码有个大概了解也是可以的,在实际工作开发中要针对合适的场景选择合适的存储方式。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。