1.WebStorsge
Cookie的不足:
- Cookie的大小被限制了;
- Cookie包含在每个HTTP请求中向服务器发送,导致多次发送重复数据。
- Cookie在网络传输时并未加密(除非整个应用都是用SSL)
1.1 Storage接口
Web Storage实际上由两部分组成:sessionStorage与localStorage。
- sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。
- localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。
1.1.1 Storage接口
interface Storage {
//同源键值对的数目
readonly attribute unsigned long length;
//通过索引获取键,索引从0开始
getter DOMString key(in unsigned long index);
//通过键获取值,键若不存在,值将返回null
getter any getItem(in DOMString key);
//存储键值对,若已存在同名键,则值将被覆盖。若用户关闭了浏览器存储或是已超
setter creator void setItem(in DOMString key, in any data);
//通过键删除值,不存在则什么也不做
deleter void removeItem(in DOMString key);
//删除storage中所有键值对,若为空则什么也不做
void clear();
};
1.1.2 浏览器支持检测
function checkStorageSupport() {
//sessionStorage
if (window.sessionStorage) {
alert('This browser supports sessionStorage');
} else {
alert('This browser does NOT support sessionStorage');
}
//localStorage
if (window.localStorage) {
alert('This browser supports localStorage');
} else {
alert('This browser does NOT support localStorage');
}
}
1.1.3 读取和存储数据
//---------------方式一--------------
//存储数据
window.sessionStorage.setItem(‘myFirstKey’, ‘myFirstValue’);
//读取数据
alert(window.sessionStorage.getItem(‘myFirstKey’));
//---------------方式二--------------
//存储数据
window.sessionStorage.myFirstKey = ‘myFirstValue’;
//读取数据
alert(window.sessionStorage.myFirstKey);
//---------------方式三--------------
for(var i=0;i<window.sessionStorage.length;i++){
var varKey = sessionStorage.key(i);
window.sessionStorage[varKey] = newValue;
}
1.1.4 处理最大配额
多数浏览器所允许的Web Storage不超过5MB,为了防止存储数据时产生超出配额的限制,可以使用捕获QUOTA_EXCEEDED_ERR异常的方法来处理,例如:
try{
sessionStorage["name"] = "Tabatha";
}catch (exception){
if (exception == QUOTA_EXCEEDED_ERR)
{
// we should tell the user their quota has been exceeded.
}
}
1.1.5 使用Storage存储数据
<body>
<h2> Storage示例</h2>
<input type="text" id="input"/>
<!-- 定义是否用Local Storage保存的数据的复选框 -->
使用Local Storage保存:<input type="checkbox" id="local"/>
<div id="show"></div>
<input type="button" value="保存数据"
οnclick="saveStorage('input');"/>
<input type="button" value="读取数据"
οnclick="loadStorage('show');"/>
<script type="text/javascript">
var saveStorage = function(id)
{
// 如果勾选了复选框,使用Local Storage保存数据
// 否则使用Session Storage保存数据
var checked = document.getElementById("local").checked;
var storage = checked ? localStorage : sessionStorage;
var target = document.getElementById(id);
storage.setItem("message" , target.value);
}
var loadStorage = function(id)
{
// 如果勾选了复选框,使用Local Storage保存数据
// 否则使用Session Storage保存数据
var checked = document.getElementById("local").checked;
var storage = checked ? localStorage : sessionStorage;
var target = document.getElementById(id);
// 读取数据
target.innerHTML = storage.getItem("message");
}
</script>
</body>
1.1.6 基于WebStorage的客户端留言板
<!DOCTYPE html>
<html>
<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title> 客户端留言板 </title>
<style type="text/css">
table {
border-collapse: collapse;
}
td , th{
border: 1px solid #888;
padding: 4px;
}
</style>
</head>
<body>
<h2>客户端留言板</h2>
<textarea id="msg" name="msg" cols="50" rows="8"></textarea><br/>
<input type="button" value="添加留言" οnclick="addMsg();"/>
<input type="button" value="清除留言" οnclick="clearMsg();"/>
<hr/>
<table style="width:550px">
<tr>
<th>留言内容</th>
<th>留言时间</th>
</tr>
<tbody id="show"></tbody>
</table>
<script type="text/javascript">
// 加载留言信息
var loadMsg = function()
{
var tb = document.getElementById("show");
// 清空原来显示的内容。
tb.innerHTML = "";
// 遍历所有留言信息
for(var i = 0 ; i < localStorage.length ; i++)
{
var key = localStorage.key(i);
var date = new Date();
date.setTime(key);
// 获取留言时间
var datestr = date.toLocaleDateString()
+ " " + date.toLocaleTimeString();
// 获取留言内容
var value = localStorage.getItem(key);
var row = tb.insertRow(i);
// 添加第一个单元格,并显示留言内容
row.insertCell(0).innerHTML = value;
// 添加第二个单元格,并显示留言内容。
row.insertCell(1).innerHTML = datestr;
}
}
var addMsg = function()
{
var msgElement = document.getElementById("msg");
var time = new Date().getTime();
// 以当前时间为key来保存留言信息
localStorage.setItem(time , msgElement.value);
msgElement.value = "";
alert("数据已保存。");
loadMsg();
}
function clearMsg()
{
// 清空Local Storage里保存的数据。
localStorage.clear();
alert("全部留言信息已被清除。");
loadMsg();
}
window.onload = loadMsg();
</script>
</body>
</html>
1.1.7 存储结构化的数据
localStorage.setItem(time , JSON.stringify(msg));
var msg = JSON.parse(msgStr);
<!DOCTYPE html>
<html>
<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title> 客户端留言板 </title>
<style type="text/css">
table {
border-collapse: collapse;
}
td , th{
border: 1px solid #888;
padding: 4px;
}
</style>
</head>
<body>
<h2>客户端留言板</h2>
留言标题:<input id="title" name="title" type="text" size="60"/><br/>
留言信息:<textarea id="content" name="content" cols="50" rows="8"></textarea><br/>
留言人:<input id="user" name="user" type="text"/><br/>
<input type="button" value="添加留言" οnclick="addMsg();"/>
<input type="button" value="清除留言" οnclick="clearMsg();"/>
<hr/>
<table style="width:750px">
<tr>
<th>留言标题</th>
<th>留言内容</th>
<th>留言人</th>
<th>留言时间</th>
</tr>
<tbody id="show"></tbody>
</table>
<script type="text/javascript">
// 加载留言信息
var loadMsg = function()
{
var tb = document.getElementById("show");
// 清空原来显示的内容。
tb.innerHTML = "";
// 遍历所有留言信息
for(var i = 0 ; i < localStorage.length ; i++)
{
var key = localStorage.key(i);
var date = new Date();
date.setTime(key);
// 获取留言时间
var datestr = date.toLocaleDateString()
+ " " + date.toLocaleTimeString();
// 获取留言字符串
var msgStr = localStorage.getItem(key);
// 把留言字符串转换成JavaScript对象
var msg = JSON.parse(msgStr);
var row = tb.insertRow(i);
// 添加第一个单元格,并显示留言内容
row.insertCell(0).innerHTML = msg.title;
// 添加第二个单元格,并显示留言内容
row.insertCell(1).innerHTML = msg.content;
// 添加第三个单元格,并显示留言内容
row.insertCell(2).innerHTML = msg.user;
// 添加第四个单元格,并显示留言内容。
row.insertCell(3).innerHTML = datestr;
}
}
var addMsg = function()
{
var titleElement = document.getElementById("title");
var contentElement = document.getElementById("content");
var userElement = document.getElementById("user");
// 将留言标题、留言内容、留言用户封装成对象
var msg = {
title: titleElement.value,
content: contentElement.value,
user: userElement.value
}
var time = new Date().getTime();
// 以当前时间为key来保存留言信息
localStorage.setItem(time , JSON.stringify(msg));
titleElement.value = "";
contentElement.value = "";
userElement.value = "";
alert("数据已保存。");
loadMsg();
}
function clearMsg()
{
// 清空Local Storage里保存的数据。
localStorage.clear();
alert("全部留言信息已被清除。");
loadMsg();
}
window.onload = loadMsg();
</script>
</body>
</html>
2.离线应用
离线应用可以在浏览器中缓存部分或全部页面。
2.1 离线应用与浏览器缓存的区别
2.2 构建离线应用
2.2.1 index.html
<!DOCTYPE html>
<html manifest="index.manifest">
<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title> 测试页面 </title>
<script type="text/javascript" src="test.js"> </script>
</head>
<body>
<img src="logo.jpg" alt="疯狂Java联盟"/>
<input id="bn" type="button" value="单击"/>
</body>
</html>
2.2.2 index.manifest
CACHE MANIFEST
#该文件的第一行必须是CACHE MANIFEST
#下面指定该清单文件的版本号
#version 1
#CACHE:后面列出的是需要缓存的资源
CACHE:
index.html
logo.jpg
#NETWORK:后面列出的不进行缓存的资源
NETWORK:
*
#FALLBACK:后面每行需要列出两个资源。
#第一个资源是处于在线状态时使用的资源。
#第二个资源是处于离线状态时所使用的资源。
FALLBACK:
#此部分是可选的
#其中第一个 URI 代表资源,第二个代表后备网页。两个 URI 必须相关,并且必须与清单文件同源。可使用通配符。
test.js offline.js
为了让Tomcat能识别index.manifest文件,需要修改Tomcat安装目录/conf/web.xml,在文件中增加一个MIME映射。
<!--将manifest后缀的文件映射成缓存清单文本文件-->
<mime-mapping>
<extension>manifest</extension>
<mime-type>text/cache-manifest</mime-type>
</mime-mapping>
Apache服务器开启支持的方式是:在conf/mime.types中添加一段代码:
test/cache-manifest manifest
IIS服务器开启方式:
右键--HTTP---MIME映射下,单击文件类型---新建---扩展名输入manifest,类型中输入test/cache-manifest
2.3 判断在线状态
navigator.onLine
window.addEventListener("offline" , function()
{
alert("您已经变成了离线状态,所有数据将会保存到本地!");
} , true);
window.addEventListener("on" , function()
{
alert("您已经变成了在线状态");
} , true);
<body>
<script type="text/javascript">
// 为离线事件绑定事件监听器
window.addEventListener("offline" , function()
{
alert("您已经变成了离线状态,所有数据将会保存到本地!");
} , true);
// 判断浏览器的在线状态
if (navigator.onLine)
{
alert("在线");
}else{
alert("离线");
}
</script>
</body>
2.4 applicationCache对象
applicationCache.onchecking = function(){
//检查manifest文件是否存在
}
applicationCache.ondownloading = function(){
//检查到有manifest或者manifest文件
//已更新就执行下载操作
//即使需要缓存的文件在请求时服务器已经返回过了
}
applicationCache.onnoupdate = function(){
//返回304表示没有更新,通知浏览器直接使用本地文件
}
applicationCache.onprogress = function(){
//下载的时候周期性的触发,可以通过它
//获取已经下载的文件个数
}
applicationCache.oncached = function(){
//下载结束后触发,表示缓存成功
}
application.onupdateready = function(){
//第二次载入,如果manifest被更新
//在下载结束时候触发
//不触发onchched
alert("本地缓存正在更新中。。。");
if(confirm("是否重新载入已更新文件")){
applicationCache.swapCache();
location.reload();
}
}
applicationCache.onobsolete = function(){
//未找到文件,返回404或者401时候触发
}
applicationCache.onerror = function(){
//其他和离线存储有关的错误
}
周期性检查服务器是否有更新
// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {
window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
// Browser downloaded a new app cache.
// Swap it in and reload the page to get the new hotness.
window.applicationCache.swapCache();
if (confirm('A new version of this site is available. Load it?')) {
window.location.reload();
}
} else {
// Manifest didn't changed. Nothing new to server.
}
}, false);
}, false);
2.4.1 swapCache.html
<!DOCTYPE html>
<html manifest="swapCache.manifest">
<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title> 检测服务器更新 </title>
</head>
<body>
<h2> 检测服务器更新 </h2>
<script type="text/javascript">
setInterval(function()
{
// 手动检查服务器是否有更新
applicationCache.update();
} , 2000);
applicationCache.onupdateready = function()
{
if(confirm("已从远程服务器下载了需要更新的缓存,是否立即更新?"))
{
// 立即更新缓存
applicationCache.swapCache();
// 重新加载页面
location.reload();
}
}
</script>
</body>
</html>
2.4.2 swapCache.manifest
CACHE MANIFEST
#version 16
CACHE:
swapCache.html
2.5 离线应用的事件监听
2.5.1 浏览器与服务器的交互
输入"http://www.baidu.com":
1)浏览器请求 http://www.baidu.com/index.html
2)服务器返回index.html
3)浏览器检查该页面是否指定manifest属性,如果没有则不会执行下面操作:
如果指定该属性,则触发checking事件,检查manifest属性所指定的manifest文件是否存在,如果不存在,则触发error事件,且不会执行第6)及后续步骤。
4)浏览器解析index.html页面,请求该页面所引起的其他资源
5)服务器返回所有的被请求的资源
6)浏览器开始处理manifest文件。重新向服务器请求manifest文件中列出的所有资源,包括index.html。
虽然已经下载过这些资源,但此时要重新下载。
7)服务器返回所有要求在本地缓存的资源。
8)浏览器下载需要在本地缓存的资源。开始下载时触发ondownloading事件;
在下载过程中不断的触发onprogress事件。
9)下载完成后触发oncache事件,表明服务器缓存完成。
重新输入"http://www.baidu.com":
1)~5)
6)浏览器检查新下载的manifest文件与本地缓存的manifest文件是否有改变:
如果manifest没有改变,则触发onnoupdate事件,则没有后续操作;
如果manifest有改变,则继续执行7)~8)
9)下载完成后,触发onupdateready事件,不是oncached事件。
<!DOCTYPE HTML>
<html manifest="event.manifest">
<head>
<meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
<meta http-equiv="Content-Type" content="text/html; charset=GBK" />
<title> 测试applicationCache事件 </title>
<script type="text/javascript">
var test = function()
{
var msg = document.getElementById("msg");
// 为applicationCache的不同事件绑定事件监听器
applicationCache.onchecking = function()
{
msg.innerHTML += "onchecking<br/>";
};
applicationCache.onnoupdate = function()
{
msg.innerHTML += "onnoupdate<br/>";
};
applicationCache.ondownloading = function()
{
msg.innerHTML += "ondownloading<br/>";
};
applicationCache.onprogress = function()
{
msg.innerHTML += "onprogress<br/>";
};
applicationCache.onupdateready = function()
{
msg.innerHTML += "onupdateready<br/>";
};
applicationCache.oncached = function()
{
msg.innerHTML+="oncached<br/>";
};
applicationCache.onerror = function()
{
msg.innerHTML += "onerror<br/>";
};
}
</script>
</head>
<body οnlοad="test();">
<h2>测试applicationCache事件</h2>
<div id="msg"></div>
</body>
</html>
为了让Tomcat能识别index.manifest文件,需要修改Tomcat安装目录/conf/web.xml,在文件中增加一个MIME映射。
<!--将manifest后缀的文件映射成缓存清单文本文件-->
<mime-mapping>
<extension>manifest</extension>
<mime-type>text/cache-manifest</mime-type>
</mime-mapping>