location.hash保存頁面狀態(tài)的技巧
hash 屬性是一個可讀可寫的字符串,該字符串是 URL 的錨部分(從 # 號開始的部分)。
語法
location.hash
在我們的項目中,有大量ajax查詢表單+結(jié)果列表的頁面,由于查詢結(jié)果是ajax返回的,當用戶點擊列表的某一項進入詳情頁之后,再點擊瀏覽器回退按鈕返回ajax查詢頁面,這時大家都知道查詢頁面的表單和結(jié)果都回到了默認狀態(tài)。
如果每次返回頁面都要重新輸入查詢條件,或有甚者還得轉(zhuǎn)到列表的第幾頁,那這種體驗用戶真的要抓狂了。
在我們的項目中,寫了一個很簡單的JavaScript基類來處理location.hash從而保存頁面狀態(tài),今天在此就分享給大家。
(本文的內(nèi)容可能對于JavaScript初學(xué)者來講有點難度,因為涉及到JS面向?qū)ο蟮闹R,如定義類、繼承、虛方法、反射等)
先看看我們的需求
我們的項目是一個基于微信的H5任務(wù)管理系統(tǒng),要完成的頁面原型如下圖所示:
需求應(yīng)該都很清晰,就是點擊查詢表單,用ajax返回查詢結(jié)果,然后點擊列表中的某一個任務(wù)進入任務(wù)詳情頁。由于管理員(項目經(jīng)理)通常會一次處理多個任務(wù),所以就會不斷在任務(wù)詳情頁跟查詢列表頁切換,這時如果按返回鍵不能保存查詢頁面狀態(tài)的話,那每次返回查詢頁面都要重新輸入查詢條件,這樣的體驗肯定是不能忍受的。
所以,我們需要想辦法將頁面狀態(tài)保存下來,以便用戶按回退鍵的時候,查詢條件和結(jié)果都還在。
解決思路
保存頁面狀態(tài)的思路有很多啦,但是我們覺得用location.hash應(yīng)該是最好的方法。
思路如下:
1.用戶輸入查詢條件并點擊確定后,我們將查詢條件序列化成一個字符串,并通過“#”將查詢條件加到url后面得到一個新的url,然后調(diào)用location.replace(新的url)修改瀏覽器地址欄中的地址。
2.當用戶按回退鍵回退到查詢頁面時,也可以說是頁面加載時,將location.hash反序列化成查詢條件,然后將查詢條件更新到查詢表單并執(zhí)行查詢即可。
思路很簡單,關(guān)鍵的地方就是location.replace方法,這個方法不僅僅是修改瀏覽器中地址欄的url,更重要的是會在window.history中替換當前頁面的記錄。如果不用location.replace方法,那么每次回退都會回退到上一個查詢條件。當然,這樣的需求可能對某些項目還有用。
最終解決方案
如果本文只是分享上面的解決思路,那價值就不大了。本文的價值應(yīng)該是我們寫的那個雖然簡單但是卻很強大的JavaScript類。
如果你看明白了上面的解決思路,那就看看這個簡單的JavaScript類吧:
(function() { if (window.HashQuery) { return; } window.HashQuery = function() { }; HashQuery.prototype = { parseFromLocation: function() { if (location.hash === '' || location.hash.length === ) { return; } var properties = location.hash.substr().split('|'); var index = ; for (var p in this) { if (!this.hasOwnProperty(p) || typeof this[p] != 'string') { continue; } if (index < properties.length) { this[p] = properties[index]; if (this[p] === '-') { this[p] = ''; } } index++; } }, updateLocation: function() { var properties = []; for (var p in this) { if (!this.hasOwnProperty(p) || typeof this[p] != 'string') { continue; } var value = this[p]; properties.push(value === '' ? '-' : value); } var url = location.origin + location.pathname + location.search + "#" + properties.join('|'); location.replace(url); } }; })();
這個類只有2個方法,HashQuery.parseFromLocation() 方法從location.hash反序列化為HashQuery子類的實例,HashQuery.updateLocation() 方法將當前HashQuery子類的實例序列化并更新到window.location。
可以看到HashQuery這個類沒有任何屬性,那是因為我們只定義了一個基類,類的屬性都在子類中進行定義。這也是符合實際的,因為查詢條件都只有在具體的頁面才知道有哪些屬性。
另外,請注意這里的序列化和反序列化。這里的序列化僅僅是利用JavaScript反射機制將實例的所有字符串屬性(按順序)的值用“|”分隔;而序列化則是將字符串用“|”分隔后,再利用反射更新到實例的屬性(按順序)。
如何使用HashQuery類
使用的時候就非常簡單了。
第一步,定義一個子類,將需要用到的查詢條件都加到字符串屬性當中,如我們的代碼:
(function() { window.TaskSearchHashQuery = function () { HashQuery.constructor.call(this); this.iterationId = ''; this.assignedUserId = ''; this.status = ''; this.keyword = ''; }; TaskSearchHashQuery.constructor = TaskSearchHashQuery; TaskSearchHashQuery.prototype = new HashQuery(); })();
第二步,在查詢頁面調(diào)用HashQuery.parseFromLocation() 和 HashQuery.updateLocation()方法即可。下面的代碼是我們完整的查詢頁面:
(function() { var urls = { list: "/app/task/list" }; var hashQuery = null; var pager = null; $(document).ready(function () { hashQuery = new TaskSearchHashQuery(); hashQuery.parseFromLocation();//在這里調(diào)用的哦,從location反序列化object updateFormByHashQuery(); $("#btnSearch").click(function() { updateHashQueryByForm(); hashQuery.updateLocation();//在這里調(diào)用的哦,將查詢條件序列化之后更新到location.hash $("#lblCount").html("加載中..."); pager.reload(); page.hideSearch(); }); pager = new ListPager("#listTasks", urls.list); pager.getPostData = function(index) { return "pageIndex=" + index + "&pageSize=" + "&projectId=" + page.projectId + "&iterationId=" + hashQuery.iterationId + "&assignedUserId=" + hashQuery.assignedUserId + "&status=" + hashQuery.status + "&keyword=" + hashQuery.keyword; }; pager.onLoaded = function() { $("#lblCount").html("共 " + $("#hfPagerTotalCount").val() + " 個任務(wù)"); $("#hfPagerTotalCount").remove(); }; pager.init(); }); function updateHashQueryByForm() { hashQuery.iterationId = $("#ddlIterations").val(); hashQuery.assignedUserId = $("#ddlUsers").val(); hashQuery.status = $("#ddlStatuses").val(); hashQuery.keyword = $("#txtKeyword").val(); }; function updateFormByHashQuery() { $("#ddlIterations").val(hashQuery.iterationId); $("#ddlUsers").val(hashQuery.assignedUserId); $("#ddlStatuses").val(hashQuery.status); $("#txtKeyword").val(hashQuery.keyword); }; })();
總結(jié)
這就是我們項目中使用location.hash來保存頁面狀態(tài)的全部知識了。不知道大家的WEB項目中是如何處理這樣的需求的呢?
以上內(nèi)容是小編給大家介紹的location.hash保存頁面狀態(tài)的技巧,希望對大家有所幫助!
相關(guān)文章
JS樹形結(jié)構(gòu)根據(jù)id獲取父級節(jié)點元素的示例代碼
這篇文章主要介紹了JS樹形結(jié)構(gòu)根據(jù)id獲取父級節(jié)點元素,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-05-05初學(xué)js插入節(jié)點appendChild insertBefore使用方法
由于可見insertBefore()方法的特性是在已有的子節(jié)點前面插入新的節(jié)點但是兩種情況結(jié)合起來發(fā)現(xiàn)insertBefore()方法插入節(jié)點,是可以在子節(jié)點列表的任意位置。2011-07-07Handtrack.js庫實現(xiàn)實時監(jiān)測手部運動(推薦)
這篇文章主要介紹了實時監(jiān)測手部運動的 JS 庫,可以實現(xiàn)很多有趣功能,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02