摘要:因?yàn)槿蝿?wù)需要添加到樹的結(jié)構(gòu)上,所以要記錄任務(wù)是添加到哪個(gè)結(jié)點(diǎn)上的,需要為每個(gè)樹結(jié)點(diǎn)添加一個(gè)作為標(biāo)識(shí)以便于在結(jié)點(diǎn)上添加任務(wù),樹狀結(jié)構(gòu)中每個(gè)結(jié)點(diǎn)的按照樹的先序遍歷將結(jié)點(diǎn)的依次儲(chǔ)存于數(shù)組中。
localStorage實(shí)現(xiàn)本地儲(chǔ)存樹形菜單
最近在寫一個(gè)Todo-list的頁(yè)面,頁(yè)面布局和操作都寫完后,想要用localStorage實(shí)現(xiàn)本地儲(chǔ)存。然而對(duì)儲(chǔ)存數(shù)據(jù)的方法一無(wú)所知,就先去了解了web的數(shù)據(jù)儲(chǔ)存。
數(shù)據(jù)儲(chǔ)存常用的web的數(shù)據(jù)儲(chǔ)存有cookie和Web Storage儲(chǔ)存機(jī)制。
cookiecookie是“小型文本文件”,主要用途是辨別用戶身份、保存用戶登錄信息。cooki是由服務(wù)器端生成、儲(chǔ)存在客戶端上的數(shù)據(jù)(通常經(jīng)過(guò)加密)。
Cookie會(huì)被附加在每個(gè)HTTP請(qǐng)求中,所以無(wú)形中增加了流量。
HTTP請(qǐng)求中的Cookie是明文傳遞的,安全性成問(wèn)題。(除非用HTTPS)
Cookie的大小限制在4KB左右。于復(fù)雜的存儲(chǔ)需求來(lái)說(shuō)是不夠用的。
Web StorageWeb Storage定義了兩種儲(chǔ)存數(shù)據(jù)的對(duì)象,localStorage和sessionStorage,它們儲(chǔ)存大小一般為5MB,機(jī)制如下:
sessionStorage由瀏覽器存儲(chǔ)某個(gè)會(huì)話(browsing session)的數(shù)據(jù),數(shù)據(jù)在當(dāng)前會(huì)話下有效,刷新頁(yè)面數(shù)據(jù)依舊存在,但在關(guān)閉頁(yè)面或?yàn)g覽器后被清除。
localStorage由瀏覽器存儲(chǔ)數(shù)據(jù),數(shù)據(jù)沒(méi)有過(guò)期時(shí)間(expiration time),也就是瀏覽器關(guān)閉再重新打開后數(shù)據(jù)仍然存在。
localStorage對(duì)象的操作在存儲(chǔ)中設(shè)置值:Storage.setItem()
從存儲(chǔ)中獲取值:Storage.getItem()
響應(yīng)存儲(chǔ)的變化:window.addEventListener("storage", function(e){});
刪除數(shù)據(jù)記錄:Storage.removeItem() 接受一個(gè)參數(shù)——你想要移除的數(shù)據(jù)項(xiàng)的鍵,然后會(huì)將對(duì)應(yīng)的數(shù)據(jù)項(xiàng)從域名對(duì)應(yīng)的存儲(chǔ)對(duì)象中移除。Storage.clear() 不接受參數(shù),只是簡(jiǎn)單地清空域名對(duì)應(yīng)的整個(gè)存儲(chǔ)對(duì)象。
在我的todo-list頁(yè)面中,用戶對(duì)樹的操作有:
在樹形菜單上添加、刪除任務(wù)分類
在任務(wù)分類中添加、刪除該分類中的任務(wù)。
也是是說(shuō)用戶的每次操作后都要更新存儲(chǔ)的數(shù)據(jù),以便在刷新頁(yè)面后顯示出用戶操作后更改過(guò)的頁(yè)面。
由于本地儲(chǔ)存只能存字符串?dāng)?shù)據(jù),所以存儲(chǔ)屬性菜單可以用到JSON。用JSON.parse將一個(gè)JavaScript對(duì)象字符串化為JSON,然后整個(gè)存入localStorage來(lái)實(shí)現(xiàn)保存。用JSON.stringify將JSON字符串解析成為一個(gè)JavaScript對(duì)象來(lái)從存儲(chǔ)中獲取值。
那么怎么用對(duì)象存儲(chǔ)樹形菜單呢,我想到了兩個(gè)方式。
一種是用一個(gè)對(duì)象treeframe存儲(chǔ)樹的結(jié)構(gòu)(所有的任務(wù)分類,不包括分類中的任務(wù))以及樹結(jié)點(diǎn)中的任務(wù),存儲(chǔ)形式如下。一旦對(duì)樹形菜單執(zhí)行任何一項(xiàng)操作,就更新treeframe對(duì)象。
var treeframe = { "任務(wù)列表":{ "使用說(shuō)明":[ { "title":"普通任務(wù)列表", "content":"可以設(shè)定任務(wù)的名稱、任務(wù)描述、任務(wù)截止時(shí)間", "endTime":"2016-05-20", "type":"normal", }, { "title":"添加新分類", "content":"通過(guò)左側(cè)自定義分類的文件夾圖標(biāo)添加新分類", "endTime":"2017-07-20", "type":"normal", } ], "今日任務(wù)":{}, "短期任務(wù)":{ "7月":{}, "8月":{}, "9月":{} }, "長(zhǎng)期任務(wù)":{} } }方式二
另一種方式是用一個(gè)對(duì)象treeframe存儲(chǔ)樹的結(jié)構(gòu),還有一個(gè)對(duì)象allTasks存儲(chǔ)所有結(jié)點(diǎn)中的任務(wù)。這種方式只需要在添加、刪除任務(wù)分類時(shí)更新樹的結(jié)構(gòu)treeframe;添加、刪除任務(wù)時(shí)更改allTasks。因?yàn)槿蝿?wù)需要添加到樹的結(jié)構(gòu)上,所以要記錄任務(wù)是添加到哪個(gè)結(jié)點(diǎn)上的,需要為每個(gè)樹結(jié)點(diǎn)添加一個(gè)id作為標(biāo)識(shí)以便于在結(jié)點(diǎn)上添加任務(wù),樹狀結(jié)構(gòu)中每個(gè)結(jié)點(diǎn)的id按照樹的先序遍歷將結(jié)點(diǎn)的id依次儲(chǔ)存于數(shù)組treeClassify.list中。為了每一個(gè)新增的結(jié)點(diǎn)的id都不與已存在的id的結(jié)點(diǎn)相同,用一個(gè)計(jì)數(shù)器fatherIdjsq來(lái)記錄可添加的新id。
存儲(chǔ)形式如下:
var treeframe = { "任務(wù)列表":{ "使用說(shuō)明":{}, "今日任務(wù)":{}, "短期任務(wù)":{ "7月":{}, "8月":{}, "9月":{} }, "長(zhǎng)期任務(wù)":{} } } var allTasks = { "list" : [ { "fatherId":"fatherId1" "title":"普通任務(wù)列表", "cnode":{"value":"普通任務(wù)列表"}, "pnode":{"value":"使用說(shuō)明"}, "content":"可以設(shè)定任務(wù)的名稱、任務(wù)描述、任務(wù)截止時(shí)間", "endTime":"2016-05-20", "type":"normal", }, { "fatherId":"fatherId5" "title":"添加新分類", "cnode":{"value":"添加新分類"}, "pnode":{"value":"使用說(shuō)明"}, "content":"通過(guò)左側(cè)自定義分類的文件夾圖標(biāo)添加新分類", "endTime":"2017-07-20", "type":"fast", }] }; var treeClassfiy = {"list":["fatherId0","fatherId1","fatherId2","fatherId3","fatherId4","fatherId5","fatherId6","fatherId8","fatherId7"]} var fatherIdjsq = 9
我覺(jué)得如果最開始寫整個(gè)todo-list時(shí)對(duì)整個(gè)頁(yè)面的功能和操作以及邏輯都理的特別清楚的話,第一種存儲(chǔ)方法一定用起來(lái)更加方便。但是我選了第二種,因?yàn)檫@樣便于我分別對(duì)樹的結(jié)構(gòu)和任務(wù)列表進(jìn)行操作,和我之前寫好的代碼比較容易融合在一起。
所以最終要存儲(chǔ)的數(shù)據(jù)如下:
- 樹狀結(jié)構(gòu)的存儲(chǔ):對(duì)象字面量形式與json的相互轉(zhuǎn)化 - 樹狀結(jié)構(gòu)中每個(gè)結(jié)點(diǎn)的id:按照樹的先序遍歷將結(jié)點(diǎn)的id依次儲(chǔ)存于數(shù)組中 - 所有任務(wù):每一個(gè)任務(wù)存儲(chǔ)于一個(gè)對(duì)象中,所有任務(wù)的對(duì)象組成一個(gè)數(shù)組 - 可以添加的新id樹形菜單的操作與儲(chǔ)存 1. 刪除任務(wù)分類
更改樹狀結(jié)構(gòu),在界面上刪除這個(gè)分類的后,將這個(gè)分類的id從存儲(chǔ)id的數(shù)組中刪去。
var jsq = 0; //計(jì)數(shù)器jsq用來(lái)記錄按先序遍歷樹,并將結(jié)點(diǎn)存于數(shù)組時(shí),該結(jié)點(diǎn)在數(shù)組中的位置 preOrder(treedata); //先序遍歷treeframe(treeframe初始儲(chǔ)存于treedata) function preOrder(treeframe) { for(var key in treeframe) { if(jsq===fatherIdArr.indexOf(choseDiv.id)) { //查找到當(dāng)前要?jiǎng)h除的結(jié)點(diǎn)(通過(guò)查看當(dāng)前要?jiǎng)h除結(jié)點(diǎn)的id在儲(chǔ)存結(jié)點(diǎn)id的數(shù)組(treeClassfiy.list)中的位置) delete treeframe[key]; //通過(guò)detele刪除對(duì)象的屬性來(lái)刪除結(jié)點(diǎn) var pos = treeClassifyIdArr.list.indexOf(choseDiv.id);//查找當(dāng)前要?jiǎng)h除的結(jié)點(diǎn)id在儲(chǔ)存結(jié)點(diǎn)id的數(shù)組中(treeClassfiy.list)的位置 treeClassifyIdArr.list.splice(pos,1); //把id從數(shù)組中刪除 fatherIdArr.splice(jsq, 1); break; } jsq++; if(typeof treeframe[key] === "object") { preOrder(treeframe[key]); } } } localStorage.setItem("treeframe", JSON.stringify(treedata)); //將更新的treedata存入設(shè)置的值treeframe中2. 添加任務(wù)分類
每次手動(dòng)添加任務(wù)分類時(shí),樹狀結(jié)構(gòu)會(huì)改變。也就是說(shuō)樹狀結(jié)構(gòu)的改變,意味著樹的結(jié)點(diǎn)增加/刪除了,存儲(chǔ)結(jié)點(diǎn)id的數(shù)組也要改變。
所以要更改樹狀結(jié)構(gòu),為新添的分類設(shè)置一個(gè)新的id,在界面上創(chuàng)建這個(gè)分類的后,將這個(gè)分類的id插入到存儲(chǔ)id的數(shù)組中。
var jsq = 0; preOrder(treedata); function preOrder(treeframe) { for(var key in treeframe) { if(jsq===fatherIdArr.indexOf(choseDiv.id)) { //找到被選中的結(jié)點(diǎn) fatherIdArr.push("fatherId"+fatherIdjsq); //先在數(shù)組中添加新的id,使新的結(jié)點(diǎn)渲染到頁(yè)面上 treeframe[key][value] = {}; //更新樹狀結(jié)構(gòu),添加結(jié)點(diǎn)(為記錄樹的結(jié)構(gòu)的對(duì)象添加屬性) preOrder2(treeframe[key]); function preOrder2(treeframe) { //jsq記錄被選中結(jié)點(diǎn)的的最后一個(gè)子節(jié)點(diǎn) for(var key in treeframe) { jsq++; if(typeof treeframe[key] === "object") { preOrder2(treeframe[key]); } } } break; } jsq++; if(typeof treeframe[key] === "object") { preOrder(treeframe[key]); } } } localStorage.setItem("treeframe", JSON.stringify(treedata)); //將更新的treedata存入設(shè)置的值treeframe中 /*此處渲染頁(yè)面*/ fatherIdArr.pop(); //新的結(jié)點(diǎn)渲染到頁(yè)面上后刪除該結(jié)點(diǎn)的id fatherIdArr.splice(jsq, 0, "fatherId"+fatherIdjsq++); //更新該結(jié)點(diǎn)id在id數(shù)組中的位置 treeClassifyIdArr.list = []; //將id數(shù)組中的元素添加到對(duì)象中 for(var j=0;j3. 刪除任務(wù) tasklistArr.splice(i,1); allTasks.list = []; for(var j=0;j4. 添加任務(wù) allTasks.list = []; for(var i=0;i5. 測(cè)試本地存儲(chǔ)是否已被填充 if(!localStorage.getItem("treeClassify")) { //本地沒(méi)有存儲(chǔ),加載初始設(shè)置的頁(yè)面 } else { //本地有存儲(chǔ),不加載初始設(shè)置的頁(yè)面,而是根據(jù)儲(chǔ)存來(lái)渲染頁(yè)面 }所有存儲(chǔ)操作的封裝var Storage = (function(mod) { // 刪除、添加、編輯快速任務(wù)和普通任務(wù)的存儲(chǔ) mod.TaskChange = function() { allTasks.list = []; for(var i=0;i需要注意的地方 加載初始設(shè)置的頁(yè)面的過(guò)程中,不需要存儲(chǔ)任何數(shù)據(jù),也就是不需要操作localStorage對(duì)象。這樣的話如果用戶不對(duì)頁(yè)面進(jìn)行操作,就沒(méi)有任何數(shù)據(jù)需要存儲(chǔ)。只有在用戶對(duì)頁(yè)面進(jìn)行操作后,才會(huì)儲(chǔ)存并再頁(yè)面再次刷新時(shí)按照儲(chǔ)存的內(nèi)容進(jìn)行頁(yè)面的渲染。
在線查看demo在線demo可供參考,歡迎review代碼,求批評(píng)、建議和交流:p
參考資料
localStorage實(shí)現(xiàn)本地儲(chǔ)存樹形菜單_demo詳說(shuō) Cookie, LocalStorage 與 SessionStorage
JSON.stringify
鏈?zhǔn)褂?Web Storage API
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/86455.html
摘要:今天來(lái)談?wù)勄岸嗣嬖囍谢旧厦看我幻娴臅r(shí)候都會(huì)被問(wèn)到的一個(gè)問(wèn)題,那就是的新特性。新表單元素元素,表示電話號(hào)碼。和通過(guò)設(shè)置和特性,可以將輸入框的數(shù)值輸入范圍限定在最低值和最高值之間。一旦為某輸入型控件設(shè)置了特性,那么此項(xiàng)必填,否則無(wú)法提交表單。 今天來(lái)談?wù)勄岸嗣嬖囍谢旧厦看我幻娴臅r(shí)候都會(huì)被問(wèn)到的一個(gè)問(wèn)題,那就是html5的新特性。這個(gè)是學(xué)習(xí)前端必須掌握的基礎(chǔ)知識(shí)。 新增的元素 html5...
摘要:轉(zhuǎn)自今天來(lái)談?wù)勄岸嗣嬖囍谢旧厦看我幻娑紩?huì)被問(wèn)到的一個(gè)問(wèn)題,那就是的新特性了。元素,表示生成密匙。和通過(guò)設(shè)置和特性,可以將輸入框的數(shù)值輸入范圍限定在最低值和最高值之間。一旦為某輸入型控件設(shè)置了特性,那么此項(xiàng)必填,否則無(wú)法提交表單。 轉(zhuǎn)自:http://hyuhan.com/2017/07/06/... 今天來(lái)談?wù)勄岸嗣嬖囍谢旧厦看我幻娑紩?huì)被問(wèn)到的一個(gè)問(wèn)題,那就是html5的新特性了。...
摘要:這一步可以參考應(yīng)用商店上傳擴(kuò)展程序一文最后終于搞定,線上可見(jiàn)學(xué)習(xí)資源建立擴(kuò)展程序插件開發(fā)攻略如何成為一名應(yīng)用開發(fā)者擴(kuò)展的開發(fā)下一步插件功能豐富化插件可在網(wǎng)頁(yè)上高亮展示標(biāo)記的文本用重構(gòu)需要使用框架嗎注本文源碼位于倉(cāng)庫(kù),線上產(chǎn)品見(jiàn)和 十一在家無(wú)聊時(shí)開發(fā)了這個(gè)項(xiàng)目。其出發(fā)點(diǎn)是想通過(guò)chrome插件,來(lái)保存網(wǎng)頁(yè)上選中的文本。后來(lái)就順手把前后端都做了(Koa2 + React): chrome...
摘要:通過(guò)采用同步的形式獲取內(nèi)容,取得內(nèi)容后,執(zhí)行文件的內(nèi)容,設(shè)置保存到中,再刪除中上個(gè)版本的文件。同步獲取文件內(nèi)容。 利用localStorage儲(chǔ)存js文件,只有在第一次訪問(wèn)該頁(yè)面的時(shí)候加載js文件,以后在訪問(wèn)的時(shí)候加載本地localStorage執(zhí)行 封裝lsFile類 有url、filename(key前綴)、lname(key)、filetext(值)屬性 var lstora...
閱讀 3161·2023-04-25 15:44
閱讀 1902·2019-08-30 13:11
閱讀 2879·2019-08-30 11:11
閱讀 3101·2019-08-29 17:21
閱讀 1334·2019-08-29 15:38
閱讀 986·2019-08-29 12:49
閱讀 1826·2019-08-28 18:19
閱讀 3249·2019-08-26 14:01