[ASP.net MVC / Html 5] WebStorage - localStorage 進階實務應用
承前篇:[Html 5] WebStorage - localStorage和sessionStorage 基本使用方法
前言
最近某案子客戶那邊的內部系統很神奇,使用者體驗很好(?),所以我正開發的系統被要求也得比照辦理=.=
假設在A頁面查詢完一個列表結果↓
※印象圖
接著使用者又瀏覽到此系統的其他頁↓
※印象圖
再誇張的是,使用者沒登出系統,可能工作偷懶什麼的,開了一個瀏覽器的tab上奇摩看一下新聞或玩個網頁遊戲後,再回到A頁↓
※印象圖
↑頁面上表單欄位、甚至查詢結果都還會殘留下來(⊙ˍ⊙)
說明
有經驗的人,一定馬上就有靈感:使用Session來做不就好了?
但
想想一下使用Session機制的流程:
1.可能要先在使用者Click 查詢按鈕時候,把表單各欄位和PageSize(每頁顯示幾筆)、CurrentPageIndex(目前第幾頁索引)儲存到Session裡
2.然後使用者可能透過瀏覽器Url網址輸入或點選超連結之類的Get Method動作進到畫面某頁時,程式再去判斷Session存不存在,如果該Session存在的話,
就把裡面的表單各欄位和PageSize(每頁顯示幾筆)、CurrentPageIndex(目前第幾頁索引)撈出來,然後放在ViewData,準備回傳給View
3.在View那邊,把表單各欄位和PageSize(每頁顯示幾筆)、CurrentPageIndex(目前第幾頁索引)等等的<input>、<select>、<textarea>各欄位的值填完後
4.再用Javascript或jQuery去click該查詢按鈕,顯示查詢結果
↑以上,使用Session實作不是說不好,因為要同時動到Controller和View,一個查詢畫面可能要花2、3小時,而我負責的系統總共有62個查詢畫面
偷懶習性的我,知道某高手一定有更快的解決辦法,能夠讓我在一天內就把62個查詢畫面全部改完XD
後來詢問結果就是要搭配以下幾個項目:
1.使用Html 5的localStorage,完全不用更動到現有Controller的程式碼,然後得在畫面上,click查詢按鈕時候,利用jQuery的serialize()函式把表單序列化,儲存到localStorage
2.在$(document).ready(function(){});裡,去判斷localStorage存不存在,有的話,把localStorage裡序列化的字串轉成JSON物件或JSON陣列
3.再把JSON物件或JSON陣列的值快速填入到畫面上表單欄位裡(應該沒人想一個一個把值assign到表單欄位吧)
4.再用Javascript或jQuery去click該查詢按鈕,顯示查詢結果
後來嘗試實作過後,開發速度真的快很多= =+ (Session做法就不理它,有新歡當然要忘了舊愛XDD)
實作
跟前篇[Html 5] WebStorage - localStorage 基本使用方法一樣,只要在View的Javascript裡寫寫程式碼就好了
考量到實務上情況可能會使用到PageSize(每頁顯示幾筆)、CurrentPageIndex(目前第幾頁索引)這兩個表單欄位
不知道大家的分頁pager是用什麼plugin還是自己打造?
我是習慣自己打造並用Ajax來查詢資料:[ASP.net MVC 4] 自己打造分頁Pager範例程式碼 (數字版,Ajax) ,因為可以做出「Loading…」的效果,使用者體驗較好,
而且我自己寫的pager會自動更新顯示目前在哪一頁(無須再靠Javascript assign pager的頁數)
直接看程式碼
不使用localStorage前
<html>
<head>
<title>不使用localStorage的頁面</title>
</head>
<body>
<!--如果使用ASP.net MVC寫View的話,記得把<form>改成
@using (Html.BeginForm("", "", FormMethod.Post, new { name = "myForm"}) )
{
裡面就是一堆表單欄位...等等
※這邊給actionName和controllerName空字串是因為待會要用jQuery Ajax查詢資料,到時候再指定呼叫的url就好
}-->
<form name="myForm" method="post" action="" style="width:800px;border: 1px solid #000000;float:left;">
輸入您對此頁的感想:<textarea name="demoTextArea"></textarea>
<br />
<br />
輸入隨便幾個字串:<input type="text" name="demoText" />
<br />
<br />
選擇您的性別:<input type="radio" name="demoRadio" value="男" checked="checked" />男 <input type="radio" name="demoRadio" value="女" />女
<br />
<br />
選擇您想進哪家公司:<br />
<input type="checkbox" name="chk鴻海" value="鴻海" />鴻海 <input type="checkbox" name="chkGoogle" value="Google" />Google<br />
<input type="checkbox" name="chkMicrosoft" value="Microsoft" />Microsoft <input type="checkbox" name="chkApple" value="Apple" />Apple
<br />
<br />
選擇您的夢想:<br />
<select name="demoSelect">
<option value="-1">請選擇</option>
<option value="買下信義區的豪宅">買下信義區的豪宅</option>
<option value="買部跑車">買部跑車</option>
<option value="脫離單身">脫離單身</option>
<option value="環遊世界">環遊世界</option>
<option value="成為微軟MVP,並一直持續連任">成為微軟MVP,並一直持續連任</option>
</select>
<br />
<br />
每頁顯示幾筆:<select name="selectPageSize">
<option value="5">5</option>
<option value="10">10</option>
<option value="15">15</option>
</select>
<br />
<input type="hidden" name="CurrentPageIndex" />
<br />
<input type="button" value="查詢" onclick="searchData(1);" />
</form>
<span style="margin-left:30px;"><a href="javascript:Logout();">登出</a></span>
<br />
<br />
<span style="margin-left:30px;"><a href="javascript:window.location.href=window.location.href"> 重新連結本頁</a></span>
<br />
<br />
<span style="margin-left:30px;"><a href="javascript:alert('不登出,直接連結到你的最愛網站,請記得輸入Url網址回本頁看看查詢結果還在不在');window.location.href='http://msdn.microsoft.com/ja-jp/windowsazure/claudia/';">連結到你的最愛網站</a></span>
<br style="clear:both;" />
<h4>顯示查詢結果:</h4>
<div id="divResult" style="width:800px;" >
</div>
<br />
<br />
<br />
<!-- ※我自己打造的pager,頁數是在表單外:[ASP.net MVC 4] 自己打造分頁Pager範例程式碼 (數字版,Ajax) http://www.dotblogs.com.tw/shadow/archive/2013/05/09/103351.aspx
且會自動更新View上面頁數的顯示,我想不出頁數該怎麼模擬,就略過吧Orz-->
<!--引用jQuery核心函式庫-->
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<!--可以做出「Loading...」效果的套件,非本文重點-->
<script src="http://malsup.github.io/jquery.blockUI.js"></script>
<script type="text/javascript">
//產生假資料是為了Demo用,因為這是.html檔,實務上應該要去Query DB裡的資料才對
var Persons = new Array();//弄一個靜態的假資料
//宣告一個js物件
function Person() {
this.Name = "";
}
//當畫面上的DOM都載入時
$(document).ready(init);
function init() {
registerRadio_CheckBox_Select();
//產生9筆假資料
GeneratePersons();
}//end init
//隨便塞資料給js物件
function GeneratePersons() {
var obj = new Person();
obj.Name = "肯幫忙全部填寫的好人,祝大大一生平安";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "可能是IT界微軟MVP的人";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "懶惰不想填寫的人";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "孤單寂寞的大叔";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "孤單寂寞的輕熟女";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "可能是車狂的大叔";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "可能需要安全感的輕熟女";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "愛好旅行的人";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "您可能立馬要準備存款了";
Persons.push(obj);//放入集合中
}
//End 塞假資料
</script>
<script type="text/javascript">
//可以做出「Loading...」效果的兩個jQuery Plugin函式,非本文重點
function blockUI() {
$("form").block({
message: '<h1>讀取中...</h1>',
css: { border: '3px solid #a00' }
});
}
function unBlockUI() {
$("form").unblock();
}
//End blockUI
</script>
<script type="text/javascript">
//查詢資料
function searchData(pageNumber)
{
//「Loading...」畫面,使用jQuery blockUI套件
//畫面會鎖住,避免使用者按完查詢鈕後又馬上再按一次查詢鈕,同時也讓使用者知道系統查詢資料中,非本文重點
blockUI();
//目前頁索引
$("input[name='CurrentPageIndex']").val((pageNumber - 1));
//查詢參數表單
var myForm = $("form[name='myForm']").serialize();//把表單序列化成QueryString
//透過ajax呼叫資料
//假裝資料讀取了2秒
setTimeout(function () {
$.ajax({
url: window.location.href,//實務上若使用ASP.net MVC的話,要改寫為"@Url.Action(actionName,controllerName)"
type: "get",//為了demo才用get,實務上查資料最好用post
async: true,//非同步執行
data: myForm,//傳遞的表單參數
cache: false,
success: function (result) {
//原本實務上應該要這樣寫↓
//$("#divResult").empty().html(result);
//result變數為從Controller回傳的Partial View,該Partial View的Action(上面的url參數)裡面的程式碼就是從DB撈出IQueryable<T>的結果資料集,
//然後在Razor那邊用C#跑迴圈組出Html Table
//為了Demo而寫的js搜尋資料版,非本文重點
showResult(myForm);
//解除blockUI(),非本文重點
unBlockUI();
},
error: function (xhr) {
//解除blockUI(),非本文重點
unBlockUI();
}
});//End ajax
}, 2000);
}
//顯示查詢結果 為了Demo才亂寫一堆js,非本文重點
function showResult(UserInputQueryString)
{
//把使用者填寫的QueryString轉成JsonObject
var userJsonObj = QueryStringToJSONObject(decodeURIComponent(UserInputQueryString));
//查詢結果
var queryResult = new Array();
//搜尋跟使用者同類型的人
$(Persons).each(function (index, jsObj) {
if (jsObj.Name == "肯幫忙全部填寫的好人,祝大大一生平安")
{
if (userJsonObj.demoTextArea != "" && userJsonObj.demoText != ""
&& (userJsonObj.chk鴻海 || userJsonObj.chkGoogle || userJsonObj.chkMicrosoft || userJsonObj.chkApple) && userJsonObj.demoSelect != "-1")
{
queryResult.push(jsObj);
}
}
if (jsObj.Name == "懶惰不想填寫的人") {
if (userJsonObj.demoTextArea == "" && userJsonObj.demoText == ""
&& (userJsonObj.chk鴻海 == undefined && userJsonObj.chkGoogle == undefined && userJsonObj.chkMicrosoft == undefined && userJsonObj.chkApple == undefined) && userJsonObj.demoSelect == "-1")
{
queryResult.push(jsObj);
}
}
if (jsObj.Name == "可能是IT界微軟MVP的人") {
if (userJsonObj.demoSelect == "成為微軟MVP,並一直持續連任" && userJsonObj.chkMicrosoft)
{
queryResult.push(jsObj);
}
}
if (jsObj.Name == "孤單寂寞的大叔")
{
if (userJsonObj.demoSelect == "脫離單身" && userJsonObj.demoRadio=="男") {
queryResult.push(jsObj);
}
}
if (jsObj.Name == "孤單寂寞的輕熟女") {
if (userJsonObj.demoSelect == "脫離單身" && userJsonObj.demoRadio == "女") {
queryResult.push(jsObj);
}
}
if (jsObj.Name == "可能是車狂的大叔") {
if (userJsonObj.demoSelect == "買部跑車" && userJsonObj.demoRadio == "男") {
queryResult.push(jsObj);
}
}
if (jsObj.Name == "可能需要安全感的輕熟女") {
if (userJsonObj.demoSelect == "買下信義區的豪宅" && userJsonObj.demoRadio == "女") {
queryResult.push(jsObj);
}
}
if (jsObj.Name == "愛好旅行的人") {
if (userJsonObj.demoSelect == "環遊世界") {
queryResult.push(jsObj);
}
}
if (jsObj.Name == "您可能立馬要準備存款了")
{
if (userJsonObj.demoSelect == "買下信義區的豪宅") {
queryResult.push(jsObj);
}
}
if ($(queryResult).size() > 0)//有結果
{
var str = "<div>您是這樣的人↓</div>" +
"<ul>";
$(queryResult).each(function (index, jsObj) {
str += "<li>";
str += jsObj.Name;
str += "</li>";
});
str += "</ul>";
$("#divResult").empty().html(str);//顯示結果
} else {
$("#divResult").empty().html("查無資料,請多嘗試,也許右鍵檢視原始碼可以幫助您");//顯示結果
}
});
}
</script>
<script type="text/javascript">
//底下的javascript很重要,請自行抽出.js檔再引用
//將queryString轉成JsonObject
//※使用此函數要注意,<input type='checkbox' />不能取相同的name,否則checkbox部份一律只會回傳一個值
function QueryStringToJSONObject(queryString) {
var pairs = queryString.split('&');
var result = {};
pairs.forEach(function (pair) {
pair = pair.split('=');
result[pair[0]] = decodeURIComponent(pair[1] || '');
});
return JSON.parse(JSON.stringify(result));
}
//處理radio、checkbox、select元素,讓它們的狀況跟以前一樣
function registerRadio_CheckBox_Select() {
//註冊radio click時,是否加上checked屬性的事件
$("input[type='radio']").click(function () {
$("input[type='radio']").removeAttr("checked");
$(this).attr("checked", true).prop("checked", true);
});
//註冊checkbox click時是否加上checked屬性的事件
$("input[type='checkbox']").click(function () {
//判斷CheckBox勾選狀態
if ($(this).prop("checked") == true) {
$(this).attr("checked", true);
} else {
$(this).attr("checked", false);
}
});
//註冊下拉選單更動時的事件
$("select").change(function () {
var value = $(this).val();//選中的值
$(this).find("option").not("[value='" + value + "']").removeAttr("selected");
$(this).find("option[value='" + value + "']").attr("selected", true);
});
}
</script>
<script type="text/javascript">
function Logout()
{//登出
alert("完成登出,畫面將導至您的最愛網站,記得回來此頁看看查詢結果還在不在");
window.location.href = "http://www.microsoft.com/taiwan/silverlight/FanClub2014/";
}
</script>
</body>
</html>
線上Demo(請用IE瀏覽):
http://shadowjapan.blob.core.windows.net/dotblogsshare/NoUseLocalStorage.html
體驗方法↓
使用localStorage之後
※這次我故意把每頁顯示幾筆PageSize的下拉選單丟到表單外,可以參考看看處理方式
<html>
<head>
<title>使用localStorage的頁面</title>
</head>
<body>
<!--如果使用ASP.net MVC寫View的話,記得把<form>改成
@using (Html.BeginForm("", "", FormMethod.Post, new { name = "myForm"}) )
{
裡面就是一堆表單欄位...等等
※這邊給actionName和controllerName空字串是因為待會要用jQuery Ajax查詢資料,到時候再指定呼叫的url就好
}-->
<form name="myForm" method="post" action="" style="width:800px;border: 1px solid #000000;float:left;">
輸入您對此頁的感想:<textarea name="demoTextArea"></textarea>
<br />
<br />
輸入隨便幾個字串:<input type="text" name="demoText" />
<br />
<br />
選擇您的性別:<input type="radio" name="demoRadio" value="男" checked="checked" />男 <input type="radio" name="demoRadio" value="女" />女
<br />
<br />
選擇您想進哪家公司:<br />
<input type="checkbox" name="chk鴻海" value="鴻海" />鴻海 <input type="checkbox" name="chkGoogle" value="Google" />Google<br />
<input type="checkbox" name="chkMicrosoft" value="Microsoft" />Microsoft <input type="checkbox" name="chkApple" value="Apple" />Apple
<br />
<br />
選擇您的夢想:<br />
<select name="demoSelect">
<option value="-1">請選擇</option>
<option value="買下信義區的豪宅">買下信義區的豪宅</option>
<option value="買部跑車">買部跑車</option>
<option value="脫離單身">脫離單身</option>
<option value="環遊世界">環遊世界</option>
<option value="成為微軟MVP,並一直持續連任">成為微軟MVP,並一直持續連任</option>
</select>
<br />
<br />
<br />
<input type="hidden" name="CurrentPageIndex" />
<input type="hidden" name="PageSize" />
<br />
<!--※↑上面幾個欄位主要展示,如何利用localStorage儲存表單欄位,待重新進入此頁時,再把欄位的值顯示出來-->
<input type="button" value="查詢" onclick="searchData(1);" />
</form>
<span style="margin-left:30px;"><a href="javascript:Logout();">登出</a></span>
<br />
<br />
<span style="margin-left:30px;"><a href="javascript:window.location.href=window.location.href">重新連結本頁</a></span>
<br />
<br />
<span style="margin-left:30px;"><a href="javascript:alert('不登出不清除localStorage,直接連結到你的最愛網站,請記得輸入Url網址或瀏覽器的上一頁,回本頁再看看查詢結果還在不在');window.location.href='http://msdn.microsoft.com/ja-jp/windowsazure/claudia/';">連結到你的最愛網站</a></span>
<br style="clear:both;" />
每頁顯示幾筆:<select name="selectPageSize" id="selectPageSize">
<option value="5">5</option>
<option value="10">10</option>
<option value="15">15</option>
</select>
<br />
<br />
<h4>顯示查詢結果:</h4>
<div id="divResult" style="width:800px;" >
</div>
<br />
<br />
<br />
<!-- ※我自己打造的pager,頁數是在表單外:[ASP.net MVC 4] 自己打造分頁Pager範例程式碼 (數字版,Ajax) http://www.dotblogs.com.tw/shadow/archive/2013/05/09/103351.aspx
且會自動更新View上面頁數的顯示,我想不出頁數該怎麼模擬,就略過吧Orz-->
<!--引用jQuery核心函式庫-->
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<!--可以做出「Loading...」效果的套件,非本文重點-->
<script src="http://malsup.github.io/jquery.blockUI.js"></script>
<script type="text/javascript">
//產生假資料是為了Demo用,因為這是.html檔,實務上應該要去Query DB裡的資料才對
var Persons = new Array();//弄一個靜態的假資料
//宣告一個js物件
function Person() {
this.Name = "";
}
//宣告一個localStorage名稱的js全域變數,專門for此頁
var localStorageName = "實務上給這個畫面一個命名吧";
//當畫面上的DOM都載入時
$(document).ready(init);
function init() {
registerRadio_CheckBox_Select();
//還原表單資料,並顯示結果
RestoreForm(localStorageName);
//產生9筆假資料
GeneratePersons();
}//end init
//隨便塞資料給js物件
//隨便塞資料給js物件
function GeneratePersons() {
var obj = new Person();
obj.Name = "肯幫忙全部填寫的好人,祝大大一生平安";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "可能是IT界微軟MVP的人";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "懶惰不想填寫的人";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "孤單寂寞的大叔";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "孤單寂寞的輕熟女";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "可能是車狂的大叔";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "可能需要安全感的輕熟女";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "愛好旅行的人";
Persons.push(obj);//放入集合中
obj = new Person();
obj.Name = "您可能立馬要準備存款了";
Persons.push(obj);//放入集合中
}
//End 塞假資料
</script>
<script type="text/javascript">
//可以做出「Loading...」效果的兩個jQuery Plugin函式,非本文重點
function blockUI() {
$("form").block({
message: '<h1>讀取中...</h1>',
css: { border: '3px solid #a00' }
});
}
function unBlockUI() {
$("form").unblock();
}
//End blockUI
</script>
<script type="text/javascript">
//查詢資料
function searchData(pageNumber)
{
//「Loading...」畫面,使用jQuery blockUI套件
//畫面會鎖住,避免使用者按完查詢鈕後又馬上再按一次查詢鈕,同時也讓使用者知道系統查詢資料中,非本文重點
blockUI();
//每頁顯示幾筆PageSize
//※因為selectPageSize下拉選單在表單外,要把它的值抓過來表單裡
var pageSize = $("select[name='selectPageSize']").val();
$("input[name='PageSize']").val(pageSize);
//目前頁索引
$("input[name='CurrentPageIndex']").val((pageNumber - 1));
//查詢參數表單
var myForm = $("form[name='myForm']").serialize();//把表單序列化成QueryString
localStorage[localStorageName] = myForm;//把QueryString存入localStorage
//透過ajax呼叫資料
//假裝資料讀取了2秒
setTimeout(function () {
$.ajax({
url: window.location.href,//實務上若使用ASP.net MVC的話,要改寫為"@Url.Action(actionName,controllerName)"
type: "get",//為了demo才用get,實務上查資料最好用post
async: true,//非同步執行
data: myForm,//傳遞的表單參數
cache: false,
success: function (result) {
//原本實務上應該要這樣寫↓
//$("#divResult").empty().html(result);
//result變數為從Controller回傳的Partial View,該Partial View的Action(上面的url參數)裡面的程式碼就是從DB撈出IQueryable<T>的結果資料集,
//然後在Razor那邊用C#跑迴圈組出Html Table
//為了Demo而寫的js搜尋資料版,非本文重點
showResult(myForm);
//解除blockUI(),非本文重點
unBlockUI();
},
error: function (xhr) {
//解除blockUI(),非本文重點
unBlockUI();
}
});//End ajax
}, 2000);
}
//顯示查詢結果 為了Demo才亂寫一堆js,非本文重點
function showResult(UserInputQueryString)
{
//把使用者填寫的QueryString轉成JsonObject
var userJsonObj = QueryStringToJSONObject( decodeURIComponent(UserInputQueryString));
//查詢結果
var queryResult = new Array();
//搜尋跟使用者同類型的人
$(Persons).each(function (index, jsObj) {
if (jsObj.Name == "肯幫忙全部填寫的好人,祝大大一生平安")
{
if (userJsonObj.demoTextArea != "" && userJsonObj.demoText != ""
&& (userJsonObj.chk鴻海 || userJsonObj.chkGoogle || userJsonObj.chkMicrosoft || userJsonObj.chkApple) && userJsonObj.demoSelect != "-1")
{
queryResult.push(jsObj);
}
}
if (jsObj.Name == "懶惰不想填寫的人") {
if (userJsonObj.demoTextArea == "" && userJsonObj.demoText == ""
&& (userJsonObj.chk鴻海 == undefined && userJsonObj.chkGoogle == undefined && userJsonObj.chkMicrosoft == undefined && userJsonObj.chkApple == undefined) && userJsonObj.demoSelect == "-1")
{
queryResult.push(jsObj);
}
}
if (jsObj.Name == "可能是IT界微軟MVP的人") {
if (userJsonObj.demoSelect == "成為微軟MVP,並一直持續連任" && userJsonObj.chkMicrosoft)
{
queryResult.push(jsObj);
}
}
if (jsObj.Name == "孤單寂寞的大叔")
{
if (userJsonObj.demoSelect == "脫離單身" && userJsonObj.demoRadio=="男") {
queryResult.push(jsObj);
}
}
if (jsObj.Name == "孤單寂寞的輕熟女") {
if (userJsonObj.demoSelect == "脫離單身" && userJsonObj.demoRadio == "女") {
queryResult.push(jsObj);
}
}
if (jsObj.Name == "可能是車狂的大叔") {
if (userJsonObj.demoSelect == "買部跑車" && userJsonObj.demoRadio == "男") {
queryResult.push(jsObj);
}
}
if (jsObj.Name == "可能需要安全感的輕熟女") {
if (userJsonObj.demoSelect == "買下信義區的豪宅" && userJsonObj.demoRadio == "女") {
queryResult.push(jsObj);
}
}
if (jsObj.Name == "愛好旅行的人") {
if (userJsonObj.demoSelect == "環遊世界") {
queryResult.push(jsObj);
}
}
if (jsObj.Name == "您可能立馬要準備存款了")
{
if (userJsonObj.demoSelect == "買下信義區的豪宅") {
queryResult.push(jsObj);
}
}
if ($(queryResult).size() > 0)//有結果
{
var str = "<div>您是這樣的人↓</div>" +
"<ul>";
$(queryResult).each(function (index, jsObj) {
str += "<li>";
str += jsObj.Name;
str += "</li>";
});
str += "</ul>";
$("#divResult").empty().html(str);//顯示結果
} else {
$("#divResult").empty().html("查無資料,請多嘗試,也許右鍵檢視原始碼可以幫助您");//顯示結果
}
});
}
</script>
<script type="text/javascript">
//底下的javascript很重要,請自行抽出.js檔再引用
//將queryString轉成JsonObject
//※使用此函數要注意,<input type='checkbox' />不能取相同的name,否則checkbox部份一律只會回傳一個值
function QueryStringToJSONObject(queryString) {
var pairs = queryString.split('&');
var result = {};
pairs.forEach(function (pair) {
pair = pair.split('=');
result[pair[0]] = decodeURIComponent(pair[1] || '');
});
return JSON.parse(JSON.stringify(result));
}
//還原表單欄位值,並顯示查詢結果
function RestoreForm(name) {
//此localStorage[name] 有存在
if (localStorage[name]) {
var queryString = localStorage[name];
var jsonObj = QueryStringToJSONObject(decodeURIComponent(queryString));
RestoreFormValues(jsonObj);//把值還原回表單
//因為「每頁顯示幾筆PageSize」下拉選單不在表單裡,所以要另外處理
var $form = $("form");//第一個表單
//從表單內的hidden欄位取值
var PageSize = Number($form.find("input[type='hidden'][name='PageSize']").val());
$("select[name='selectPageSize']").val(PageSize);//更改下拉選項
var js查詢按鈕Obj = $("input[value='查詢']")[0];//轉型成js物件
if (js查詢按鈕Obj) { //有查詢按鈕
$(js查詢按鈕Obj).click();//點擊它,顯示資料
} else {
//因為有些查詢畫面,無須下條件(表單欄位)查詢,單純查看畫面然後點選哪一頁(pager),且無查詢按鈕
//為了還原原本使用者瀏覽的資料,要依據「每頁顯示幾筆」和「目前在哪一頁」來顯示上次瀏覽的資料
//※如果偷懶的話,其實可以不用寫if判斷查詢按鈕在不在畫面上,直接使用底下三行來Run就好了XD
var CurrentPageIndex = Number($form.find("input[type='hidden'][name='CurrentPageIndex']").val());
var pageNumber = CurrentPageIndex + 1;//目前頁數
searchData(pageNumber);//查詢資料
}
}
}
//把JsonObj裡的每個屬性值填入到各表單欄位
function RestoreFormValues(jsonObj) {
// reset form values from jsonObject
$.each(jsonObj, function (name, val) {
var $el = $('[name="' + name + '"]'),
type = $el.attr('type');
switch (type) {
case 'checkbox':
$el.prop("checked",true).attr('checked', true);
break;
case 'radio':
$el.filter('[value="' + val + '"]').prop("checked", true).attr('checked', true);
break;
default://預設是input元素,也有可能是textarea
$el.val(val);
}
});
}
//處理radio、checkbox、select元素,讓它們的狀況跟以前一樣
function registerRadio_CheckBox_Select() {
//註冊radio click時,是否加上checked屬性的事件
$("input[type='radio']").click(function () {
$("input[type='radio']").removeAttr("checked");
$(this).attr("checked", true).prop("checked", true);
});
//註冊checkbox click時是否加上checked屬性的事件
$("input[type='checkbox']").click(function () {
//判斷CheckBox勾選狀態
if ($(this).prop("checked") == true) {
$(this).attr("checked", true);
} else {
$(this).attr("checked", false);
}
});
//註冊下拉選單更動時的事件
$("select").change(function () {
var value = $(this).val();//選中的值
$(this).find("option").not("[value='" + value + "']").removeAttr("selected");
$(this).find("option[value='" + value + "']").attr("selected", true);
});
}
</script>
<script type="text/javascript">
function Logout()
{//登出
//記得localStorage要清掉,不清也是可以,看需求
//或者如果是後台網站的話,在登入畫面click登入按鈕那個時候,清除localStorage也是可以
localStorage.clear();//清除此網站的localStorage
alert("完成登出並清除localStorage,畫面將導至您的最愛網站,請記得回來此頁看看查詢結果還在不在");
window.location.href = "http://www.microsoft.com/taiwan/silverlight/FanClub2014/";
}
</script>
</body>
</html>
附上關鍵的程式碼片段↓,要使用localStorage還原原本的表單欄位值並顯示原先的查詢結果
請先準備以下三個JS函式
//將queryString轉成JsonObject
//※使用此函數要注意,<input type='checkbox' />不能取相同的name,否則checkbox部份一律只會回傳一個值
function QueryStringToJSONObject(queryString) {
var pairs = queryString.split('&');
var result = {};
pairs.forEach(function (pair) {
pair = pair.split('=');
result[pair[0]] = decodeURIComponent(pair[1] || '');
});
return JSON.parse(JSON.stringify(result));
}
//還原表單欄位值,並顯示查詢結果
function RestoreForm(name) {
//此localStorage[name] 有存在
if (localStorage[name]) {
var queryString = localStorage[name];
var jsonObj = QueryStringToJSONObject(decodeURIComponent(queryString));
RestoreFormValues(jsonObj);//把值還原回表單
//因為「每頁顯示幾筆PageSize」下拉選單不在表單裡,所以要另外處理
var $form = $("form");//第一個表單
//從表單內的hidden欄位取值
var PageSize = Number($form.find("input[type='hidden'][name='PageSize']").val());
$("select[name='selectPageSize']").val(PageSize);//更改下拉選項
var js查詢按鈕Obj = $("input[value='查詢']")[0];//轉型成js物件
if (js查詢按鈕Obj) { //有查詢按鈕
$(js查詢按鈕Obj).click();//點擊它,顯示資料
} else {
//因為有些查詢畫面,無須下條件(表單欄位)查詢,單純查看畫面然後點選哪一頁(pager),且無查詢按鈕
//為了還原原本使用者瀏覽的資料,要依據「每頁顯示幾筆」和「目前在哪一頁」來顯示上次瀏覽的資料
//※如果偷懶的話,其實可以不用寫if判斷查詢按鈕在不在畫面上,直接使用底下三行來Run就好了XD
var CurrentPageIndex = Number($form.find("input[type='hidden'][name='CurrentPageIndex']").val());
var pageNumber = CurrentPageIndex + 1;//目前頁數
searchData(pageNumber);//查詢資料
}
}
}
//把JsonObj裡的每個屬性值填入到各表單欄位
function RestoreFormValues(jsonObj) {
// reset form values from jsonObject
$.each(jsonObj, function (name, val) {
var $el = $('[name="' + name + '"]'),
type = $el.attr('type');
switch (type) {
case 'checkbox':
$el.prop("checked",true).attr('checked', true);
break;
case 'radio':
$el.filter('[value="' + val + '"]').prop("checked", true).attr('checked', true);
break;
default://預設是input元素,也有可能是textarea
$el.val(val);
}
});
}
再來要做的事情就很輕鬆,View加三行程式碼就好,開發速度超快XD
↑在$(document).ready();裡,去還原表單欄位的值&顯示之前的查詢結果
這樣就差不多了,↓剩下就是自行決定什麼時候要幫使用者清除localStorage
線上Demo(請用IE瀏覽):
http://shadowjapan.blob.core.windows.net/dotblogsshare/UseLocalStorage.html
體驗方法↓
※2014-07-13追記:發現Demo網頁有一個小Bug
因為鴻海Checkbox的name我取名為chk鴻海,可能是Windows Azure或程式碼哪邊不支援中文命名,所以勾選鴻海的話,鴻海Checkbox無法勾選回去,糗了XD
※2014-07-14追記:
在鍥而不捨追查下,發現chk鴻海勾不回去的原因在這行↓
var myForm = $("form[name='myForm']").serialize();
jQuery的serialize()函式很貼心地,會自動把表單欄位的name和value全都做encodeURIComponent
所以在還原表單欄位值時↓
解決寫法有兩種
第一種↓
或第二種↓
個人偏向第二種,因為我自己開發上,已把RestoreForm的JS函式抽到.js檔,所以改一次就全部都套用了
以上Bug已修正,並更新部落格文章和線上Demo,請安心服用。
結語
以後有keep住值的需求,不只是傳統的Session、Cookie,新玩意的localStorage有時候會出乎意料地加快開發速度。
參考文章:
Turning the Querystring into a JSON object using JavaScript
Use jquery to re-populate form with JSON data - StackOverflow