Asp.net mvc 中使用LocalStorage
目前使用比较多的本地存储方案有比如Flash SharedObject、Google Gears、Cookie、LocalStorage、User Data、Open Database等方案。综合比较了下,最终选择了LocalStorage。
关于他们之间的比较,我在此不多说了,本文着重实现。想了解他们之间的区别的朋友可以参考一下这几个园友博客:
1.JavaScript本地存储实践: http://www.cnblogs.com/xupeiyu/p/4447443.html
2.HTML5 LocalStorage 本地存储:http://www.cnblogs.com/xiaowei0705/archive/2011/04/19/2021372.html
这里是用UserData和HTML5-LocalStorage结合的方式,来取代cookie。参考修改了alien朋友的LocalStorage.js,<<传送门>>
做个简单的比较:
UserData:仅IE可用
Flash:存储空间大
Google Gears:存储空间没限制,需装额外的插件
HTML5-LocalStorage:官方建议每个站点可以本地存储5M的内容
原本的js我进行了些修改,如下:
1 Namespace = new Object(); 2 // 全局对象仅仅存在register函数,参数为名称空间全路径,如"Grandsoft.GEA" 3 Namespace.register = function(fullNS) { 4 // 将命名空间切成N部分, 比如Grandsoft、GEA等 5 var nsArray = fullNS.split(‘.‘); 6 var sEval = ""; 7 var sNS = ""; 8 for (var i = 0; i < nsArray.length; i++) { 9 if (i != 0) sNS += "."; 10 sNS += nsArray[i]; 11 // 依次创建构造命名空间对象(假如不存在的话)的语句 12 // 比如先创建Grandsoft,然后创建Grandsoft.GEA,依次下去 13 sEval += "if (typeof(" + sNS + ") == ‘undefined‘) " + sNS + " = new Object();" 14 } 15 if (sEval != "") eval(sEval); 16 } 17 18 /** 19 * 注册命名空间 20 */ 21 Namespace.register(‘SummitLocalStorage‘); 22 23 /** 24 * @class SummitLocalStorage.LocalStorage 25 * 跨浏览器的本地存储实现。高级浏览器使用localstorage,ie使用UserData。虽然说是本地存储,也请不要存储过大数据,最好不要大于64K. 26 * 因为ie下UserData每页最大存储是64k。 27 * @singleton 28 * @author zhaoxianlie (xianliezhao@foxmail.com) 29 */ 30 (function() { 31 /** 32 * 验证字符串是否合法的键名 33 * @param {Object} key 待验证的key 34 * @return {Boolean} true:合法,false:不合法 35 * @private 36 */ 37 function _isValidKey(key) { 38 return (new RegExp("^[^\\x00-\\x20\\x7f\\(\\)<>@,;:\\\\\\\"\\[\\]\\?=\\{\\}\\/\\u0080-\\uffff]+\x24")).test(key); 39 } 40 41 //所有的key 42 var _clearAllKey = "_baidu.ALL.KEY_"; 43 44 /** 45 * 创建并获取这个input:hidden实例 46 * @return {HTMLInputElement} input:hidden实例 47 * @private 48 */ 49 function _getInstance() { 50 //把UserData绑定到input:hidden上 51 var _input = null; 52 //是的,不要惊讶,这里每次都会创建一个input:hidden并增加到DOM树种 53 //目的是避免数据被重复写入,提早造成“磁盘空间写满”的Exception 54 _input = document.createElement("input"); 55 _input.type = "hidden"; 56 _input.addBehavior("#default#userData"); 57 document.body.appendChild(_input); 58 return _input; 59 } 60 61 /** 62 * 将数据通过UserData的方式保存到本地,文件名为:文件名为:config.key[1].xml 63 * @param {String} key 待存储数据的key,和config参数中的key是一样的 64 * @param {Object} config 待存储数据相关配置 65 * @cofnig {String} key 待存储数据的key 66 * @config {String} value 待存储数据的内容 67 * @config {String|Object} [expires] 数据的过期时间,可以是数字,单位是毫秒;也可以是日期对象,表示过期时间 68 * @private 69 */ 70 function __setItem(key, config) { 71 try { 72 var input = _getInstance(); 73 //创建一个Storage对象 74 var storageInfo = config || {}; 75 //设置过期时间 76 if (storageInfo.expires) { 77 var expires; 78 //如果设置项里的expires为数字,则表示数据的能存活的毫秒数 79 if (‘number‘ == typeof storageInfo.expires) { 80 expires = new Date(); 81 expires.setTime(expires.getTime() + storageInfo.expires); 82 } 83 input.expires = expires.toUTCString(); 84 } 85 86 //存储数据 87 input.setAttribute(storageInfo.key, storageInfo.value); 88 //存储到本地文件,文件名为:storageInfo.key[1].xml 89 input.save(storageInfo.key); 90 } catch (e) {} 91 } 92 93 /** 94 * 将数据通过UserData的方式保存到本地,文件名为:文件名为:config.key[1].xml 95 * @param {String} key 待存储数据的key,和config参数中的key是一样的 96 * @param {Object} config 待存储数据相关配置 97 * @cofnig {String} key 待存储数据的key 98 * @config {String} value 待存储数据的内容 99 * @config {String|Object} [expires] 数据的过期时间,可以是数字,单位是毫秒;也可以是日期对象,表示过期时间 100 * @private 101 */ 102 function _setItem(key, config) { 103 //保存有效内容 104 __setItem(key, config); 105 106 //下面的代码用来记录当前保存的key,便于以后clearAll 107 var result = _getItem({ 108 key: _clearAllKey 109 }); 110 if (result) { 111 result = { 112 key: _clearAllKey, 113 value: result 114 }; 115 } else { 116 result = { 117 key: _clearAllKey, 118 value: "" 119 }; 120 } 121 122 if (!(new RegExp("(^|\\|)" + key + "(\\||$)", ‘g‘)).test(result.value)) { 123 result.value += "|" + key; 124 //保存键 125 __setItem(_clearAllKey, result); 126 } 127 } 128 129 /** 130 * 提取本地存储的数据 131 * @param {String} config 待获取的存储数据相关配置 132 * @cofnig {String} key 待获取的数据的key 133 * @return {String} 本地存储的数据,获取不到时返回null 134 * @example 135 * SummitLocalStorage.LocalStorage.get({ 136 * key : "username" 137 * }); 138 * @private 139 */ 140 function _getItem(config) { 141 try { 142 var input = _getInstance(); 143 //载入本地文件,文件名为:config.key[1].xml 144 input.load(config.key); 145 //取得数据 146 return input.getAttribute(config.key) || null; 147 } catch (e) { 148 return null; 149 } 150 } 151 152 /** 153 * 移除某项存储数据 154 * @param {Object} config 配置参数 155 * @cofnig {String} key 待存储数据的key 156 * @private 157 */ 158 function _removeItem(config) { 159 try { 160 var input = _getInstance(); 161 //载入存储区块 162 input.load(config.key); 163 //移除配置项 164 input.removeAttribute(config.key); 165 //强制使其过期 166 var expires = new Date(); 167 expires.setTime(expires.getTime() - 1); 168 input.expires = expires.toUTCString(); 169 input.save(config.key); 170 171 //从allkey中删除当前key 172 //下面的代码用来记录当前保存的key,便于以后clearAll 173 var result = _getItem({ 174 key: _clearAllKey 175 }); 176 if (result) { 177 result = result.replace(new RegExp("(^|\\|)" + config.key + "(\\||$)", ‘g‘), ‘‘); 178 result = { 179 key: _clearAllKey, 180 value: result 181 }; 182 //保存键 183 __setItem(_clearAllKey, result); 184 } 185 186 } catch (e) {} 187 } 188 189 //移除所有的本地数据 190 function _clearAll() { 191 result = _getItem({ 192 key: _clearAllKey 193 }); 194 if (result) { 195 var allKeys = result.split("|"); 196 var count = allKeys.length; 197 for (var i = 0; i < count; i++) { 198 if (!!allKeys[i]) { 199 _removeItem({ 200 key: allKeys[i] 201 }); 202 } 203 } 204 } 205 } 206 207 208 /** 209 * 获取所有的本地存储数据对应的key 210 * @return {Array} 所有的key 211 * @private 212 */ 213 function _getAllKeys() { 214 var result = []; 215 var keys = _getItem({ 216 key: _clearAllKey 217 }); 218 if (keys) { 219 keys = keys.split(‘|‘); 220 for (var i = 0, len = keys.length; i < len; i++) { 221 if (!!keys[i]) { 222 result.push(keys[i]); 223 } 224 } 225 } 226 return result; 227 } 228 229 /** 230 * 判断当前浏览器是否支持本地存储:window.localStorage 231 * @return {Boolean} true:支持;false:不支持 232 * @remark 支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+ 233 * @private 234 var _isSupportLocalStorage = ((‘localStorage‘ in window) && (window[‘localStorage‘] !== null)), 235 _isSupportUserData = !!jQuery.browser.ie; 236 */ 237 var _isSupportLocalStorage = ((‘localStorage‘ in window) && (window[‘localStorage‘] !== null)); 238 239 SummitLocalStorage.LocalStorage = { 240 /** 241 * 如果支持本地存储,返回true;否则返回false 242 * @type Boolean 243 */ 244 isAvailable: _isSupportLocalStorage || _isSupportUserData, 245 246 /** 247 * 将数据进行本地存储(只能存储字符串信息) 248 * <pre><code> 249 * //保存单个对象 250 * SummitLocalStorage.LocalStorage.set({ 251 * key : "username", 252 * value : "baiduie", 253 * expires : 3600 * 1000 254 * }); 255 * //保存对个对象 256 * SummitLocalStorage.LocalStorage.set([{ 257 * key : "username", 258 * value : "baiduie", 259 * expires : 3600 * 1000 260 * },{ 261 * key : "password", 262 * value : "zxlie", 263 * expires : 3600 * 1000 264 * }]); 265 * </code></pre> 266 * @param {Object} obj 待存储数据相关配置,可以是单个JSON对象,也可以是由多个JSON对象组成的数组 267 * <ul> 268 * <li><b>key</b> : String <div class="sub-desc">待存储数据的key,务必将key值起的复杂一些,如:baidu.username</div></li> 269 * <li><b>value</b> : String <div class="sub-desc">待存储数据的内容</div></li> 270 * <li><b>expires</b> : String/Object (Optional)<div class="sub-desc">数据的过期时间,可以是数字,单位是毫秒;也可以是日期对象,表示过期时间</div></li> 271 * </ul> 272 */ 273 set: function(obj) { 274 //保存单个对象 275 var _set_ = function(config) { 276 //key校验 277 if (!_isValidKey(config.key)) { 278 return; 279 } 280 281 //待存储的数据 282 var storageInfo = config || {}; 283 284 //支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+ 285 if (_isSupportLocalStorage) { 286 window.localStorage.setItem(storageInfo.key, storageInfo.value); 287 if (config.expires) { 288 var expires; 289 //如果设置项里的expires为数字,则表示数据的能存活的毫秒数 290 if (‘number‘ == typeof storageInfo.expires) { 291 expires = new Date(); 292 expires.setTime(expires.getTime() + storageInfo.expires); 293 } 294 295 window.localStorage.setItem(storageInfo.key + ".expires", expires); 296 } 297 } else if (_isSupportUserData) { //IE7及以下版本,采用UserData方式 298 _setItem(config.key, storageInfo); 299 } 300 }; 301 302 //判断传入的参数是否为数组 303 if (obj && obj.constructor === Array && obj instanceof Array) { 304 for (var i = 0, len = obj.length; i < len; i++) { 305 _set_(obj[i]); 306 } 307 } else if (obj) { 308 _set_(obj); 309 } 310 }, 311 312 /** 313 * 提取本地存储的数据 314 * <pre><code> 315 * //获取某一个本地存储,返回值为:{key:"",value:"",expires:""},未取到值时返回值为:null 316 * var rst = SummitLocalStorage.LocalStorage.get({ 317 * key : "username" 318 * }); 319 * //获取多个本地存储,返回值为:["","",""],未取到值时返回值为:[null,null,null] 320 * SummitLocalStorage.LocalStorage.get([{ 321 * key : "username" 322 * },{ 323 * key : "password" 324 * },{ 325 * key : "sex" 326 * }]); 327 * </code></pre> 328 * @param {String} obj 待获取的存储数据相关配置,支持单个对象传入,同样也支持多个对象封装的数组格式 329 * @config {String} key 待存储数据的key 330 * @return {String} 本地存储的数据,传入为单个对象时,返回单个对象,获取不到时返回null;传入为数组时,返回为数组 331 */ 332 get: function(obj) { 333 //获取某一个本地存储 334 var _get_ = function(config) { 335 //结果 336 var result = null; 337 if (typeof config === "string") config = { 338 key: config 339 }; 340 //key校验 341 if (!_isValidKey(config.key)) { 342 return result; 343 } 344 345 //支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+ 346 if (_isSupportLocalStorage) { 347 result = window.localStorage.getItem(config.key); 348 //过期时间判断,如果过期了,则移除该项 349 if (result) { 350 var expires = window.localStorage.getItem(config.key + ".expires"); 351 result = { 352 value: result, 353 expires: expires ? new Date(expires) : null 354 }; 355 if (result && result.expires && result.expires < new Date()) { 356 result = null; 357 window.localStorage.removeItem(config.key); 358 window.localStorage.removeItem(config.key + ".expires"); 359 } 360 } 361 } else if (_isSupportUserData) { //IE7及以下版本,采用UserData方式 362 //这里不用单独判断其expires,因为UserData本身具有这个判断 363 result = _getItem(config); 364 if (result) { 365 result = { 366 value: result 367 }; 368 } 369 } 370 371 return result ? result.value : null; 372 }; 373 374 var rst = null; 375 //判断传入的参数是否为数组 376 if (obj && obj.constructor === Array && obj instanceof Array) { 377 rst = []; 378 for (var i = 0, len = obj.length; i < len; i++) { 379 rst.push(_get_(obj[i])); 380 } 381 } else if (obj) { 382 rst = _get_(obj); 383 } 384 return rst; 385 }, 386 387 /** 388 * 移除某一项本地存储的数据 389 * <pre><code> 390 * //删除一个本地存储项 391 * SummitLocalStorage.LocalStorage.remove({ 392 * key : "username" 393 * }); 394 * //删除多个本地存储项目 * 395 * SummitLocalStorage.LocalStorage.remove([{ 396 * key : "username" 397 * },{ 398 * key : "password" 399 * },{ 400 * key : "sex" 401 * }]); 402 * </code></pre> 403 * @param {String} obj 待移除的存储数据相关配置,支持移除某一个本地存储,也支持数组形式的批量移除 404 * @config {String} key 待移除数据的key 405 * @return 无 406 */ 407 remove: function(obj) { 408 //移除某一项本地存储的数据 409 var _remove_ = function(config) { 410 //支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+ 411 if (_isSupportLocalStorage) { 412 window.localStorage.removeItem(config.key); 413 window.localStorage.removeItem(config.key + ".expires"); 414 } else if (_isSupportUserData) { //IE7及以下版本,采用UserData方式 415 _removeItem(config); 416 } 417 }; 418 419 //判断传入的参数是否为数组 420 if (obj && obj.constructor === Array && obj instanceof Array) { 421 for (var i = 0, len = obj.length; i < len; i++) { 422 _remove_(obj[i]); 423 } 424 } else if (obj) { 425 _remove_(obj); 426 } 427 }, 428 429 /** 430 * 清除所有本地存储的数据 431 * <pre><code> 432 * SummitLocalStorage.LocalStorage.clearAll(); 433 * </code></pre> 434 */ 435 clearAll: function() { 436 //支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+ 437 if (_isSupportLocalStorage) { 438 window.localStorage.clear(); 439 } else if (_isSupportUserData) { //IE7及以下版本,采用UserData方式 440 _clearAll(); 441 } 442 }, 443 444 //保存单个对象到本地 445 //save: function(EmployeeID, EmployeeName, EmployeeDescription,EmployeeAge) { 446 // SummitLocalStorage.LocalStorage.set({ 447 // /* key: EmployeeID + EmployeeName + EmployeeDescription+EmployeeAge,*/ 448 // key:"wangbiaoTest3", 449 // value: "{ ‘员工编号’: ‘" + EmployeeID + "’,‘员工姓名’: ‘" + EmployeeName + "’, ‘员工描述’:‘" + EmployeeDescription + "’, ‘员工年龄’:‘"+EmployeeAge+"’}", 450 // expires: 3600 * 1000 /*单位:ms*/ 451 // }); 452 //}, 453 save: function (result) { 454 SummitLocalStorage.LocalStorage.set({ 455 key: "summit", 456 value: result, 457 expires: 3600 * 1000 /*单位:ms*/ 458 }); 459 }, 460 461 /** 462 * 获取所有的本地存储数据对应的key 463 * <pre><code> 464 * var keys = SummitLocalStorage.LocalStorage.getAllKeys(); 465 * </code></pre> 466 * @return {Array} 所有的key 467 */ 468 getAllKeys: function() { 469 var result = []; 470 //支持本地存储的浏览器:IE8+、Firefox3.0+、Opera10.5+、Chrome4.0+、Safari4.0+、iPhone2.0+、Andrioid2.0+ 471 if (_isSupportLocalStorage) { 472 var key; 473 for (var i = 0, len = window.localStorage.length; i < len; i++) { 474 key = window.localStorage.key(i); 475 if (!/.+\.expires$/.test(key)) { 476 result.push(key); 477 } 478 } 479 } else if (_isSupportUserData) { //IE7及以下版本,采用UserData方式 480 result = _getAllKeys(); 481 } 482 483 return result; 484 } 485 }; 486 })();
接着先上控制器,准备数据:
1 [HttpPost] 2 public ActionResult LocalStorage_Read() 3 { 4 var model = new List<UserModel> { 5 new UserModel{Id=1,Name="summit",Age=20,Description="t5est",CreateOn=DateTime.Now}, 6 new UserModel{Id=2,Name="alex",Age=20,Description="t5est",CreateOn=DateTime.Now}, 7 new UserModel{Id=3,Name="glant",Age=20,Description="t5est",CreateOn=DateTime.Now} 8 }; 9 return Json(model); 10 }
View中代码如下:
1 <script src="~/Scripts/jquery-2.1.1.js"></script> 2 <script src="~/Scripts/localstorage.js"></script> 3 4 <script type="text/javascript"> 5 $(function () { 6 7 var Alldata = SummitLocalStorage.LocalStorage.get({ 8 key: "summit" 9 }); 10 if (Alldata != null) { 11 ReadStorageData(Alldata); 12 } 13 else { 14 StorageData(); 15 } 16 17 function StorageData() { 18 //把配置数据写到LocalStorage中 19 $.ajax({ 20 type: "POST", 21 url: "/home/LocalStorage_Read", 22 success: function (result) { 23 var obj = JSON.stringify(result); 24 SummitLocalStorage.LocalStorage.save(obj); 25 Alldata = SummitLocalStorage.LocalStorage.get({ key: "summit" }); 26 ReadStorageData(Alldata); 27 } 28 }); 29 } 30 31 function ReadStorageData(Alldata) { 32 var data = JSON.parse(Alldata);//这里获取到的值是一个数组,你可以按照你的想法去操作 33 var str = ""; 34 for (var i = 0; i < data.length; i++) { 35 str +="---"+ data[i].Id; 36 } 37 alert(str); 38 } 39 }); 40 </script>
FireFox下效果如图:
Google:
IE:
现在来解释一下上面的代码:
SummitLocalStorage.LocalStorage.get({ key: "summit" }); 获取指定Key的值
SummitLocalStorage.LocalStorage.save(obj) ; save是js封装的一个方法:用于保存一个对象,你也可以指定固定的参数传递.
在Asp.net MVC中使用LocalStorage还是挺方便的,LocalStorage容量为5M,是Cookies的N倍,有需要的朋友可以考虑一下。