在线考试系统使用HTML5 storage实现本地存储(科帮网)
最近在做在线考试系统时遇到这样一个问题,就是当考生考试时可能出出现断网、关闭浏览器,刷新等问题,此时数据又没有实时写入数据库,所以造成数据丢失问题,,所以这里就需要用到本地存储,一开始想到的是用cookie,但是cookie缺失太小了是有4k。本地持久化存储一直是本地客户端程序优于 web 程序的一个方面。对于本地应用程序,操作系统会一共一个抽象层,用于存储和获取特定于应用程序的数据,例如用户设置或者运行时状态。这些值可以被存储于注册表、INI 文件,或者其他什么地方,这取决于操作系统的实现。如果你的本地应用程序需要不简单是键值对形式的本地存储,你也可以使用嵌入式数据库、发明你自己的文件格式,或者其他很多种解决方案。
UserData实现方式:
userData行为通过将数据写入一个UserData存储区(UserDatastore)来保存数据,userData可以将数据以XML格式保存在客户端计算机上,如果你用的是 Windows 2000 或者 Windows XP,是保存在C:\Documents and Settings\Liming\UserData\文件夹下(如果操作系统不是安装在C盘,那么C就应该是操作系统所在的分区)。
该数据将一直存在,除非你人为删除或者用脚本设置了该数据的失效期。
userData行为提供了一个比Cookie更具有动态性和更大容量的数据结构。每页的UserData存储区数据大小可以达到64 Kb,每个域名可以达到640 Kb。
userData行为通过sessions为每个对象分配UserData存储区。使用save和load方法将UserData存储区数据保存在缓存(cache)中。一旦UserData存储区保存以后,即使IE浏览器关闭或者刷新了,下一次进入该页面,数据也能够重新载入而不会丢失。
但是,UserData是IE的东西,所以其他浏览器不兼容。
HTML5 storage实现方式:
HTML5 storage提供了一种方式让网站能够把信息存储到你本地的计算机上,并再以后需要的时候进行获取。这个概念和cookie相似,区别是它是为了更大容量存储设计的。Cookie的大小是受限的,并且每次你请求一个新的页面的时候cookie都会被发送过去。HTML5的storage是存储在你的计算机上,网站在页面加载完毕后可以通过Javascript来获取这些数据。
由于HTML5 storage IE8一下浏览器 所有IE8一下版本要做判断使用UserData的方式实现。具体代码已封装。说明一下 jQuery.browser建议弃用,可以使用jQuery.support来代替。
页面展示:
<!doctype html>
<html>
<head>
<title>科帮网在线考试本地存储Powered by 52itstyle</title>
<meta charset="utf-8" />
<script src="../js/jquery-1.8.3.js"></script>
<script src="../js/localstorage.js"></script>
<script src="../js/jquery.utils.js"></script>
<script type="text/javascript">
var studentID = "007";
var ExamID = "52itstyle";
var quesNumber = 3;
$(function(){
showQuestion();
$("input").click(function(){
var QuestionID = $(this).attr("name");
var ExamAnswer = $(this).val();
qext.LocalStorage.save(studentID,ExamID,QuestionID,ExamAnswer);
});
});
/**
* 读取本地存储答案并展示(科帮网http://www.52itstyle.top)
* java爱好者QQ群:26490602
*/
function showQuestion(){
for(var i=1;i<=quesNumber;i++){
var rst = getPerQuesInfo(i);
if(null!=rst){
var obj = eval("("+rst+")");
var examAnswer = obj.ExamAnswer;
$("input").val(examAnswer)
}
}
}
/**
* 获取单个试题信息(科帮网http://www.52itstyle.top)
* java爱好者QQ群:26490602
*/
function getPerQuesInfo(QuestionID){
var examKey = studentID+ExamID+QuestionID;
var rst = qext.LocalStorage.get({
key : examKey
});
return rst;
}
</script>
</head>
<body>
<div id="1">成吉思汗有几个老婆?</div>
<div>
<input type="radio" value="A" name="1" />A 1
<input type="radio" value="B" name="1"/>B 2
<input type="radio" value="C" name="1"/>C 3
<input type="radio" value="D" name="1"/>D 4
</div>
<div>成吉思汗有几个老婆?</div>
<div>
<input type="radio" value="A" name="2" />A 1
<input type="radio" value="B" name="2"/>B 2
<input type="radio" value="C" name="2"/>C 3
<input type="radio" value="D" name="2"/>D 4
</div>
<div>小伟有几个老婆?</div>
<div>
<input type="radio" value="A" name="3" />A 1
<input type="radio" value="B" name="3"/>B 2
<input type="radio" value="C" name="3"/>C 3
<input type="radio" value="D" name="3"/>D 无数
</div>
<a href="http://www.52itstyle.top/">传送门</a>
</body>
</html>本地存储JS封装:localstorage.js不得不佩服此人的代码掉渣天。
/**
* 注册命名空间
* @param {String} fullNS 完整的命名空间字符串,如qui.dialog
* @param {Boolean} isIgnorSelf 是否忽略自己,默认为false,不忽略
* @author zhaoxianlie(xianliezhao@foxmail.com)
* @example
* window.registNS("QingFeed.Text.Bold");
*/
window.registNS = function(fullNS,isIgnorSelf){
//命名空间合法性校验依据
var reg = /^+*/i;
// 将命名空间切成N部分, 比如baidu.libs.Firefox等
var nsArray = fullNS.split('.');
var sEval = "";
var sNS = "";
var n = isIgnorSelf ? nsArray.length - 1 : nsArray.length;
for (var i = 0; i < n; i++){
//命名空间合法性校验
if(!reg.test(nsArray)) {
throw new Error("Invalid namespace:" + nsArray + "");
return ;
}
if (i != 0) sNS += ".";
sNS += nsArray;
// 依次创建构造命名空间对象(假如不存在的话)的语句
sEval += "if(typeof(" + sNS + ")=='undefined') " + sNS + "=new Object();else " + sNS + ";";
}
//生成命名空间
if (sEval != "") {
return eval(sEval);
}
return {};
};
/**
* 注册命名空间
*/
window.registNS('qext');
/**
* @class qext.LocalStorage
* 跨浏览器的本地存储实现。高级浏览器使用localstorage,ie使用UserData。虽然说是本地存储,也请不要存储过大数据,最好不要大于64K.
* 因为ie下UserData每页最大存储是64k。
* @singleton
* @author zhaoxianlie (xianliezhao@foxmail.com)
*/
(function(){
/**
* 验证字符串是否合法的键名
* @param {Object} key 待验证的key
* @return {Boolean} true:合法,false:不合法
* @private
*/
function _isValidKey(key) {
return (new RegExp("^[^\\x00-\\x20\\x7f\\(\\)<>@,;:\\\\\\\"\\[\\]\\?=\\{\\}\\/\\u0080-\\uffff]+\x24")).test(key);
}
//所有的key
var _clearAllKey = "_baidu.ALL.KEY_";
/**
* 创建并获取这个input:hidden实例
* @return {HTMLInputElement} input:hidden实例
* @private
*/
function _getInstance(){
//把UserData绑定到input:hidden上
var _input = null;
//是的,不要惊讶,这里每次都会创建一个input:hidden并增加到DOM树种
//目的是避免数据被重复写入,提早造成“磁盘空间写满”的Exception
_input = document.createElement("input");
_input.type = "hidden";
_input.addBehavior("#default#userData");
document.body.appendChild(_input);
return _input;
}
/**
* 将数据通过UserData的方式保存到本地,文件名为:文件名为:config.key.xml
* @param {String} key 待存储数据的key,和config参数中的key是一样的
* @param {Object} config 待存储数据相关配置
* @cofnig {String} key 待存储数据的key
* @config {String} value 待存储数据的内容
* @config {String|Object} 数据的过期时间,可以是数字,单位是毫秒;也可以是日期对象,表示过期时间
* @private
*/
function __setItem(key,config){
try {
var input = _getInstance();
//创建一个Storage对象
var storageInfo = config || {};
//设置过期时间
if(storageInfo.expires) {
var expires;
//如果设置项里的expires为数字,则表示数据的能存活的毫秒数
if ('number' == typeof storageInfo.expires) {
expires = new Date();
expires.setTime(expires.getTime() + storageInfo.expires);
}
input.expires = expires.toUTCString();
}
//存储数据
input.setAttribute(storageInfo.key,storageInfo.value);
//存储到本地文件,文件名为:storageInfo.key.xml
input.save(storageInfo.key);
} catch (e) {
}
}
/**
* 将数据通过UserData的方式保存到本地,文件名为:文件名为:config.key.xml
* @param {String} key 待存储数据的key,和config参数中的key是一样的
* @param {Object} config 待存储数据相关配置
* @cofnig {String} key 待存储数据的key
* @config {String} value 待存储数据的内容
* @config {String|Object} 数据的过期时间,可以是数字,单位是毫秒;也可以是日期对象,表示过期时间
* @private
*/
function _setItem(key,config){
//保存有效内容
__setItem(key,config);
//下面的代码用来记录当前保存的key,便于以后clearAll
var result = _getItem({key : _clearAllKey});
if(result) {
result = {
key : _clearAllKey,
value : result
};
} else {
result = {
key : _clearAllKey,
value : ""
};
}
if(!(new RegExp("(^|\\|)" + key + "(\\||$)",'g')).test(result.value)) {
result.value += "|" + key;
//保存键
__setItem(_clearAllKey,result);
}
}
/**
* 提取本地存储的数据
* @param {String} config 待获取的存储数据相关配置
* @cofnig {String} key 待获取的数据的key
* @return {String} 本地存储的数据,获取不到时返回null
* @example
* qext.LocalStorage.get({
* key : "username"
* });
* @private
*/
function _getItem(config){
try {
var input = _getInstance();
//载入本地文件,文件名为:config.key.xml
input.load(config.key);
//取得数据
return input.getAttribute(config.key) || null;
} catch (e) {
return null;
}
}
/**
* 移除某项存储数据
* @param {Object} config 配置参数
* @cofnig {String} key 待存储数据的key
* @private
*/
function _removeItem(config){
try {
var input = _getInstance();
//载入存储区块
input.load(config.key);
//移除配置项
input.removeAttribute(config.key);
//强制使其过期
var expires = new Date();
expires.setTime(expires.getTime() - 1);
input.expires = expires.toUTCString();
input.save(config.key);
//从allkey中删除当前key
//下面的代码用来记录当前保存的key,便于以后clearAll
var result = _getItem({key : _clearAllKey});
if(result) {
result = result.replace(new RegExp("(^|\\|)" + config.key + "(\\||$)",'g'),'');
result = {
key : _clearAllKey,
value : result
};
//保存键
__setItem(_clearAllKey,result);
}
} catch (e) {
}
}
//移除所有的本地数据
function _clearAll(){
result = _getItem({key : _clearAllKey});
if(result) {
var allKeys = result.split("|");
var count = allKeys.length;
for(var i = 0;i < count;i++){
if(!!allKeys) {
_removeItem({key:allKeys});
}
}
}
}
/**
* 获取所有的本地存储数据对应的key
* @return {Array} 所有的key
* @private
*/
function _getAllKeys(){
var result = [];
var keys = _getItem({key : _clearAllKey});
if(keys) {
keys = keys.split('|');
for(var i = 0,len = keys.length;i < len;i++){
if(!!keys) {
result.push(keys);
}
}
}
return result ;
}
/**
* 判断当前浏览器是否支持本地存储:window.localStorage
* @return {Boolean} true:支持;false:不支持
* @remark 支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+
* @private
*/
var _isSupportLocalStorage = (('localStorage' in window) && (window['localStorage'] !== null)),
_isSupportUserData = !!jQuery.browser.ie;
qext.LocalStorage = {
/**
* 如果支持本地存储,返回true;否则返回false
* @type Boolean
*/
isAvailable : _isSupportLocalStorage || _isSupportUserData,
/**
* 将数据进行本地存储(只能存储字符串信息)
* <pre><code>
* //保存单个对象
* qext.LocalStorage.set({
* key : "username",
* value : "baiduie",
* expires : 3600 * 1000
* });
* //保存对个对象
* qext.LocalStorage.set([{
* key : "username",
* value : "baiduie",
* expires : 3600 * 1000
* },{
* key : "password",
* value : "zxlie",
* expires : 3600 * 1000
* }]);
* </code></pre>
* @param {Object} obj 待存储数据相关配置,可以是单个JSON对象,也可以是由多个JSON对象组成的数组
* <ul>
* <li><b>key</b> : String <div class="sub-desc">待存储数据的key,务必将key值起的复杂一些,如:baidu.username</div></li>
* <li><b>value</b> : String <div class="sub-desc">待存储数据的内容</div></li>
* <li><b>expires</b> : String/Object (Optional)<div class="sub-desc">数据的过期时间,可以是数字,单位是毫秒;也可以是日期对象,表示过期时间</div></li>
* </ul>
*/
set : function(obj){
//保存单个对象
var _set_ = function(config){
//key校验
if(!_isValidKey(config.key)) {return;}
//待存储的数据
var storageInfo = config || {};
//支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+
if(_isSupportLocalStorage) {
window.localStorage.setItem(storageInfo.key,storageInfo.value);
if(config.expires) {
var expires;
//如果设置项里的expires为数字,则表示数据的能存活的毫秒数
if ('number' == typeof storageInfo.expires) {
expires = new Date();
expires.setTime(expires.getTime() + storageInfo.expires);
}
window.localStorage.setItem(storageInfo.key + ".expires",expires);
}
} else if(_isSupportUserData) { //IE7及以下版本,采用UserData方式
_setItem(config.key,storageInfo);
}
};
//判断传入的参数是否为数组
if(obj && obj.constructor === Array && obj instanceof Array){
for(var i = 0,len = obj.length;i < len;i++){
_set_(obj);
}
}else if(obj){
_set_(obj);
}
},
/**
* 提取本地存储的数据
* <pre><code>
* //获取某一个本地存储,返回值为:{key:"",value:"",expires:""},未取到值时返回值为:null
* var rst = qext.LocalStorage.get({
* key : "username"
* });
* //获取多个本地存储,返回值为:["","",""],未取到值时返回值为:
* qext.LocalStorage.get([{
* key : "username"
* },{
* key : "password"
* },{
* key : "sex"
* }]);
* </code></pre>
* @param {String} obj 待获取的存储数据相关配置,支持单个对象传入,同样也支持多个对象封装的数组格式
* @config {String} key 待存储数据的key
* @return {String} 本地存储的数据,传入为单个对象时,返回单个对象,获取不到时返回null;传入为数组时,返回为数组
*/
get : function(obj){
//获取某一个本地存储
var _get_ = function(config){
//结果
var result = null;
if(typeof config === "string") config = {key : config};
//key校验
if(!_isValidKey(config.key)) {return result;}
//支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+
if(_isSupportLocalStorage) {
result = window.localStorage.getItem(config.key);
//过期时间判断,如果过期了,则移除该项
if(result) {
var expires = window.localStorage.getItem(config.key + ".expires");
result = {
value : result,
expires : expires ? new Date(expires) : null
};
if(result && result.expires && result.expires < new Date()) {
result = null;
window.localStorage.removeItem(config.key);
window.localStorage.removeItem(config.key + ".expires");
}
}
} else if(_isSupportUserData) { //IE7及以下版本,采用UserData方式
//这里不用单独判断其expires,因为UserData本身具有这个判断
result = _getItem(config);
if(result) {
result = { value : result };
}
}
return result ? result.value : null;
};
var rst = null;
//判断传入的参数是否为数组
if(obj && obj.constructor === Array && obj instanceof Array){
rst = [];
for(var i = 0,len = obj.length;i < len;i++){
rst.push(_get_(obj));
}
}else if(obj){
rst = _get_(obj);
}
return rst;
},
/**
* 移除某一项本地存储的数据
* <pre><code>
* //删除一个本地存储项
* qext.LocalStorage.remove({
* key : "username"
* });
* //删除多个本地存储项目 *
* qext.LocalStorage.remove([{
* key : "username"
* },{
* key : "password"
* },{
* key : "sex"
* }]);
* </code></pre>
* @param {String} obj 待移除的存储数据相关配置,支持移除某一个本地存储,也支持数组形式的批量移除
* @config {String} key 待移除数据的key
* @return 无
*/
remove : function(obj){
//移除某一项本地存储的数据
var _remove_ = function(config){
//支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+
if(_isSupportLocalStorage) {
window.localStorage.removeItem(config.key);
window.localStorage.removeItem(config.key + ".expires");
} else if(_isSupportUserData){ //IE7及以下版本,采用UserData方式
_removeItem(config);
}
};
//判断传入的参数是否为数组
if(obj && obj.constructor === Array && obj instanceof Array){
for(var i = 0,len = obj.length;i < len;i++){
_remove_(obj);
}
}else if(obj){
_remove_(obj);
}
},
/**
* 清除所有本地存储的数据
* <pre><code>
* qext.LocalStorage.clearAll();
* </code></pre>
*/
clearAll : function(){
//支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+
if(_isSupportLocalStorage) {
window.localStorage.clear();
} else if(_isSupportUserData) { //IE7及以下版本,采用UserData方式
_clearAll();
}
},
//保存单个对象到本地
save:function(StudentID,ExamID,QuestionID,ExamAnswer){
qext.LocalStorage.set({
key : StudentID+ExamID+QuestionID,
value : "{StudentID’: ‘"+StudentID+"’, ‘ExamID’: ‘"+ExamID+"’, ‘QuestionID’: ‘"+QuestionID+"’,‘ExamAnswer’: ‘"+ExamAnswer+"’}",
expires : 3600 * 1000/*单位:ms*/
});
},
/**
* 获取所有的本地存储数据对应的key
* <pre><code>
* var keys = qext.LocalStorage.getAllKeys();
* </code></pre>
* @return {Array} 所有的key
*/
getAllKeys : function(){
var result = [];
//支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+
if(_isSupportLocalStorage) {
var key;
for(var i = 0,len = window.localStorage.length;i < len;i++){
key = window.localStorage.key(i);
if(!/.+\.expires$/.test(key)) {
result.push(key);
}
}
} else if(_isSupportUserData) { //IE7及以下版本,采用UserData方式
result = _getAllKeys();
}
return result;
}
};
})();
演示地址:http://www.52itstyle.top/localstorage/index.html
下来,学习一下。谢谢:) 这个项目太棒勒!下下来学习下!
页:
[1]